<script lang="ts">
  import { TEST_MENU } from "./menus";
  import { type ContentAction } from "svelte-floating-ui";
  import TestCtxMenu2Item from "./TestCtxMenu2Item.svelte";
  import { kbd } from "@melt-ui/svelte/internal/helpers";
  import { writable, type Writable } from "svelte/store";
  import outclick from "$lib/util/actions/outclick";
  import { LIST_PAGENAV_N } from "$lib/util/constants";
  import { clamp } from "$lib/util/functions";

  export let menu = TEST_MENU;
  export let menuOpen = false;
  export let floatingContent: ContentAction | (() => void) = () => {};
  export let mainMenuClose: (() => void) | undefined = undefined;
  export let submenuClose: (() => void) | undefined = undefined;

  let menuElements: TestCtxMenu2Item[] = [];
  let openSubmenu: Writable<string | null> = writable(null);

  export function open() {
    menuOpen = true;
  }

  export function close() {
    menuOpen = false;
  }

  export function toggle() {
    if (menuOpen) close();
    else open();
  }

  export function focusFirst() {
    if (menuElements.length > 0 && getCurrentIndex() === -1) menuElements[0].focus();
  }

  function getCurrentIndex(): number {
    return menuElements.findIndex((elm) => elm.getIsActive());
  }

  function onKeydown(e: KeyboardEvent) {
    if (handleMenuNavigation(e)) {
      e.stopPropagation();
    }
  }

  // https://github.com/melt-ui/melt-ui/blob/develop/src/lib/builders/menu/create.ts

  function handleMenuNavigation(e: KeyboardEvent): boolean {
    e.preventDefault();

    // Index of the currently focused item in the candidate nodes array
    const currentIndex = getCurrentIndex();
    if (currentIndex === -1) return false;

    // Calculate the index of the next menu item
    let nextIndex = currentIndex;
    switch (e.key) {
      case kbd.ARROW_DOWN:
        if (e.ctrlKey) nextIndex = menuElements.length - 1;
        else nextIndex++;
        break;
      case kbd.ARROW_UP:
        if (e.ctrlKey) nextIndex = 0;
        else nextIndex--;
        break;
      case kbd.HOME:
        nextIndex = 0;
        break;
      case kbd.END:
        nextIndex = menuElements.length - 1;
        break;
      case kbd.PAGE_DOWN:
        nextIndex += LIST_PAGENAV_N;
        break;
      case kbd.PAGE_UP:
        nextIndex -= LIST_PAGENAV_N;
        break;
      case kbd.ARROW_RIGHT:
        if (menu[currentIndex].submenu) {
          menuElements[currentIndex].focus(true, true);
        }
        return true;
      case kbd.ARROW_LEFT:
        if (submenuClose) {
          submenuClose();
          return true;
        }
        return false;
      default:
        return false;
    }
    nextIndex = clamp(nextIndex, 0, menuElements.length - 1);
    menuElements[nextIndex].focus(false);
    return true;
  }

  function onOutclick() {
    console.log("outclick");
    menuOpen = false;
    openSubmenu.set(null);
  }

  const condOutclick = submenuClose ? () => {} : outclick;
</script>

<svelte:window
  on:keydown={(e) => {
    if (e.key === kbd.ESCAPE) {
      onOutclick();
    }
  }}
/>

{#if menuOpen}
  <div
    class="ctxmenu"
    role="menu"
    use:floatingContent
    tabindex={submenuClose ? -1 : 0}
    on:keydown={onKeydown}
    use:condOutclick
    on:outclick={onOutclick}
  >
    {#each menu as menuItem, i}
      <TestCtxMenu2Item
        {menuItem}
        {openSubmenu}
        mainMenuClose={mainMenuClose ?? close}
        bind:this={menuElements[i]}
      />
    {/each}
  </div>
{/if}
