<script>
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { browser } from '$app/environment';
  import { onMount, onDestroy, getContext } from 'svelte';
  import TinyGesture from 'tinygesture';

  import { boot, subscribeToEvents } from '$lib/apiServer';
  import { currentUser, logins, channelsList, messages } from '$lib/store';

  import ChannelList from '$lib/components/ChannelList.svelte';
  import CreateChannelForm from '$lib/components/CreateChannelForm.svelte';

  let events = null;
  let gesture = null;

  let pageContext = getContext('page');
  let { children } = $props();
  let loading = $state(true);
  let channel = $derived($page.params.channel);

  function onBooted(boot) {
    currentUser.update(() => ({
      id: boot.login.id,
      username: boot.login.name
    }));
    logins.update((value) => value.setLogins(boot.logins));
    channelsList.update((value) => value.setChannels(boot.channels));
    messages.update((value) => value.setMessages(boot.messages));
  }

  function setUpGestures() {
    if (!browser) {
      // Meaningless if we're not in a browser, so...
      return;
    }
    gesture = new TinyGesture(window);
    gesture.on('swiperight', (event) => {
      pageContext.showMenu = true;
    });
    gesture.on('swipeleft', (event) => {
      pageContext.showMenu = false;
    });
  }

  onMount(async () => {
    let response = await boot();
    switch (response.status) {
      case 200:
        onBooted(response.data);
        events = subscribeToEvents(response.data.resume_point);
        break;
      case 401:
        currentUser.update(() => null);
        goto('/login');
        break;
      case 503:
        currentUser.update(() => null);
        goto('/setup');
        break;
      default:
        // TODO: display error.
        break;
    }
    setUpGestures();

    loading = false;
  });

  onDestroy(async () => {
    if (events !== null) {
      events.close();
    }
    if (gesture !== null) {
        gesture.destroy();
    }
  });
</script>

<svelte:head>
  <title>pilcrow</title>
</svelte:head>

{#if loading}
  <h2>Loading&hellip;</h2>
{:else}
  <div id="interface" class="p-2">
    <nav id="sidebar" data-expanded={pageContext.showMenu}>
      <div class="channel-list">
        <ChannelList active={channel} channels={$channelsList.channels} />
      </div>
      <div class="create-channel">
        <CreateChannelForm />
      </div>
    </nav>
    <main class="pl-4">
      {@render children?.()}
    </main>
  </div>
{/if}

<style>
  /* Just some global CSS variables, don't mind them.
   */
  :root {
    --app-bar-height: 68px;
    --input-row-height: 2rem;
    --interface-padding: 16px;
  }

  /* This should help minimize swipe-to-go-back behaviour, enabling our
   * swipe-to-reveal-channel-menu behaviour. It won't work in all cases; in iOS
   * Safari, when swiping from the screen edge, the OS gets th event and
   * handles it before the browser does.
   */
  html, body {
      overscroll-behavior-x: none;
  }

  #interface {
    margin: unset;
    display: grid;
    grid-template:
      'side main' 1fr
      / auto 1fr;
    height: calc(100vh - var(--app-bar-height));

    @media (width > 640px) {
      --overlay: static;
      --translate: 0;
    }
  }
  nav {
    grid-area: side;
    background-color: rgb(var(--color-surface-800));
    inset: auto auto 0 0;
    padding: 0.25rem;
    position: var(--overlay, absolute);
    transition: translate 300ms ease-out;
    width: 21rem;
    height: calc(100vh - var(--app-bar-height) - var(--interface-padding));
    z-index: 10;
  }
  main {
    grid-area: main;
    height: calc(100vh - var(--app-bar-height) - var(--interface-padding));
  }
  .channel-list {
    height: calc(
      100vh - var(--app-bar-height) - var(--interface-padding) - var(--input-row-height)
    );
    overflow: auto;
  }
  nav[data-expanded='false'] {
    translate: var(--translate, -100% 0);
  }
</style>
