<script lang="ts">
  import "@fontsource-variable/inter";
  import "../style/app.pcss"; // eslint-disable-line no-relative-import-paths/no-relative-import-paths

  import { onMount } from "svelte";
  import { page } from "$app/stores";
  import { afterNavigate } from "$app/navigation";
  import { setLocale } from "$i18n/i18n-svelte";
  import type { LayoutData } from "./$types";

  import {
    clientState,
    initClientState,
    setNavbarWidth,
    setQueuebarWidth,
  } from "$lib/stores/clientState";
  import { updateTheme } from "$lib/stores/theme";
  import {
    mainWidth,
    mainPhone,
    screenWidth,
    screenHeight,
    mainSmall,
    mainElm,
    headerColor,
  } from "$lib/stores/layout";
  import { clamp, getEventCoords } from "$lib/util/functions";
  import { WIDTH_PHONE, WIDTH_SMALL } from "$lib/util/constants";

  import Navbar from "$lib/components/nav/Navbar.svelte";
  import Playerbar from "$lib/components/player/Playerbar.svelte";
  import DummyText from "$lib/components/ui/DummyText.svelte";
  import NavbarMobile from "$lib/components/nav/NavbarMobile.svelte";
  import NavbarMobileLandscape from "$lib/components/nav/NavbarMobileLandscape.svelte";
  import PlayerbarMobile from "$lib/components/player/PlayerbarMobile.svelte";
  import FixedHeader from "$lib/components/header/FixedHeader.svelte";

  export let data: LayoutData;
  // at the very top, set the locale before you access the store and before the actual rendering takes place
  setLocale(data.locale);

  // Layout boundaries
  const NAVBAR_MIN = 150;
  const NAVBAR_MAX = 500;
  const QUEUEBAR_MIN = 250;
  const CONTENT_MIN = 300;

  let scrollPos = 0;

  // Draggable layout
  let navbarElm: HTMLElement;
  let navbarResizing = false;

  let queuebarElm: HTMLElement;
  let queuebarResizing = false;

  let mobileLandscape = false;
  $: mobileLandscape = $screenHeight < WIDTH_PHONE && $screenWidth > WIDTH_PHONE;
  let showNavbar = false;
  $: showNavbar = $screenWidth >= WIDTH_SMALL && !mobileLandscape;
  let showQueue = false;
  $: showQueue = showNavbar && $clientState.showQueue;

  let navbarWidth = 0;
  $: navbarWidth = showNavbar ? $clientState.navbarWidth : 0;
  let queuebarWidth = 0;
  $: queuebarWidth = showQueue
    ? clamp(
        $clientState.queuebarWidth,
        QUEUEBAR_MIN,
        $screenWidth - navbarWidth - CONTENT_MIN
      )
    : 0;
  $: $mainWidth = $screenWidth - navbarWidth - queuebarWidth;

  $: navbarWidthSty = showNavbar ? navbarWidth : 0;
  $: queuebarWidthSty = showQueue ? queuebarWidth : 0;

  function initResizeNavbar(e: MouseEvent) {
    if (e.button !== 0) return;
    window.addEventListener("mousemove", resizeNavbar, false);
    window.addEventListener("mouseup", stopResizeNavbar, false);
    navbarResizing = true;
    e.preventDefault();
  }

  function initResizeNavbarTouch(_e: TouchEvent) {
    window.addEventListener("touchmove", resizeNavbar, false);
    window.addEventListener("touchend", stopResizeNavbar, false);
    navbarResizing = true;
  }

  function resizeNavbar(e: MouseEvent | TouchEvent) {
    const pos = getEventCoords(e)!.x - navbarElm.offsetLeft;
    setNavbarWidth(
      clamp(
        pos,
        NAVBAR_MIN,
        Math.min(NAVBAR_MAX, $screenWidth - QUEUEBAR_MIN - CONTENT_MIN)
      )
    );
  }

  function stopResizeNavbar() {
    window.removeEventListener("mousemove", resizeNavbar, false);
    window.removeEventListener("mouseup", stopResizeNavbar, false);
    window.removeEventListener("touchmove", resizeNavbar, false);
    window.removeEventListener("touchend", stopResizeNavbar, false);
    navbarResizing = false;
  }

  function initResizeQueuebar(e: MouseEvent) {
    if (e.button !== 0) return;
    window.addEventListener("mousemove", resizeQueuebar, false);
    window.addEventListener("mouseup", stopResizeQueuebar, false);
    queuebarResizing = true;
    e.preventDefault();
  }

  function initResizeQueuebarTouch(_e: TouchEvent) {
    window.addEventListener("touchmove", resizeQueuebar, false);
    window.addEventListener("touchend", stopResizeQueuebar, false);
    queuebarResizing = true;
  }

  function resizeQueuebar(e: MouseEvent | TouchEvent) {
    const pos = queuebarElm.offsetLeft + queuebarElm.clientWidth - getEventCoords(e)!.x;
    setQueuebarWidth(
      clamp(pos, QUEUEBAR_MIN, $screenWidth - navbarWidth - CONTENT_MIN)
    );
  }

  function stopResizeQueuebar() {
    window.removeEventListener("mousemove", resizeQueuebar, false);
    window.removeEventListener("mouseup", stopResizeQueuebar, false);
    window.removeEventListener("touchmove", resizeQueuebar, false);
    window.removeEventListener("touchend", stopResizeQueuebar, false);
    queuebarResizing = false;
  }

  function onScroll() {
    scrollPos = $mainElm?.scrollTop || 0;
  }

  function onDragEnd() {
    delete document.body.dataset.dragType;
  }

  // Restore scroll state on navigation
  export const snapshot = {
    capture: () => {
      const pos = $mainElm!.scrollTop;
      $mainElm!.scrollTo(0, 0);
      return pos;
    },
    restore: (y) => {
      $mainElm!.scrollTo(0, y);
    },
  };

  afterNavigate(() => {
    headerColor.set(null);
  });

  onMount(() => {
    initClientState();
    updateTheme();
  });
</script>

<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
  id="app"
  class:mobile={!showNavbar && !mobileLandscape}
  class:mobile-landscape={mobileLandscape}
  bind:clientWidth={$screenWidth}
  bind:clientHeight={$screenHeight}
  on:dragend={onDragEnd}
>
  <div
    id="main-content"
    style={`--navbar-width: ${navbarWidthSty}px; --queuebar-width: ${queuebarWidthSty}px;`}
  >
    {#if showNavbar}
      <nav class="sidebar" bind:this={navbarElm}>
        <!-- svelte-ignore a11y-no-static-element-interactions -->
        <div
          class="handle right-0"
          on:mousedown={initResizeNavbar}
          on:touchstart|passive={initResizeNavbarTouch}
          class:active={navbarResizing}
        />
        <Navbar />
      </nav>
    {:else if mobileLandscape}
      <nav class="sidebar">
        <NavbarMobileLandscape />
      </nav>
    {/if}
    {#if showQueue}
      <aside class="sidebar" bind:this={queuebarElm}>
        <!-- svelte-ignore a11y-no-static-element-interactions -->
        <div
          class="handle left-0"
          on:mousedown={initResizeQueuebar}
          on:touchstart|passive={initResizeQueuebarTouch}
          class:active={queuebarResizing}
        />
        <DummyText />
      </aside>
    {/if}
    <header>
      <FixedHeader {scrollPos} />
    </header>
    <main
      bind:this={$mainElm}
      class:mainSmall={$mainSmall}
      class:mainPhone={$mainPhone}
      on:scroll={onScroll}
    >
      {#if !$page.data.header?.fading}
        <div class="h-12" />
      {/if}
      <slot />
      {#if !showNavbar && !mobileLandscape}
        <!-- Spacer to ensure enough bottom space to scroll beyond floating playerbar -->
        <div class="h-24" />
      {/if}
    </main>
  </div>
  {#if showNavbar && !mobileLandscape}
    <Playerbar />
  {:else if !mobileLandscape}
    <PlayerbarMobile />
    <NavbarMobile />
  {/if}
</div>

<style lang="postcss">
  #app {
    display: grid;
    grid-template:
      "main-content" calc(100vh - 90px)
      "player" 90px / 1fr;
    height: 100%;
    overflow: hidden;

    &.mobile {
      grid-template:
        "main-content" calc(100vh - 3rem)
        "player" 3rem / 1fr;
    }

    &.mobile-landscape {
      grid-template: "main-content" 100vh;
    }
  }

  #main-content {
    position: relative;
    grid-area: main-content / main-content / main-content / main-content;
    display: grid;
    grid-template: "sidebar main right-sidebar" 1fr / var(--navbar-width) 1fr var(
        --queuebar-width
      );
  }

  .mobile-landscape > #main-content {
    grid-template: "sidebar main" 1fr/10rem 1fr;
  }

  main {
    grid-area: main;

    overflow-x: hidden;
    overflow-y: auto;
  }

  header {
    grid-area: main;
    height: 3rem;
    z-index: 20;
  }

  nav {
    grid-area: sidebar / sidebar / sidebar / sidebar;
  }

  aside {
    grid-area: right-sidebar / right-sidebar / right-sidebar / right-sidebar;
    z-index: 60;
  }

  .handle {
    position: absolute;
    z-index: 61;
    width: 4px;
    cursor: ew-resize;
    opacity: 0;
    transition: opacity 0.4s;
    @apply bg-base-content/50;

    &.active {
      @apply bg-primary;
      opacity: 1;
    }

    &:hover {
      opacity: 1;
    }
  }

  .sidebar {
    position: relative;
    overflow-x: hidden;
    overflow-y: auto;
    @apply bg-base-300;

    & > div {
      height: 100%;
    }
  }
</style>
