<script lang="ts">
  type CssClass = string | (string | false | null | undefined)[];

  type Props = {
    completions: string[];
    popover_class?: CssClass;
    search_input_class?: CssClass;
    search_input_element?: HTMLInputElement;
    search_value: string;
    value: string;
  };

  let {
    completions,
    popover_class,
    search_input_class,
    search_input_element = $bindable(),
    search_value = $bindable(),
    value = $bindable(),
  }: Props = $props();

  let focused = $state(false);
  let popover_element = $state<HTMLDivElement | undefined>();

  function handle_component_focusin() {
    focused = true;
    popover_element?.showPopover();
  }

  function handle_component_focusout() {
    focused = false;
    setTimeout(() => {
      // TODO: There's still an edge case, where a click with a
      // mousedown-to-mouseup duration greater than the delay here will cause
      // the popover to hide.
      if (!focused) {
        popover_element?.hidePopover();
      }
    }, 250);
  }

  function handle_completion_click(completion: string) {
    value = completion;
    search_input_element?.focus();
    popover_element?.hidePopover();
  }

  function handle_search_keydown(ev: KeyboardEvent) {
    if (ev.key === "Escape") {
      popover_element?.hidePopover();
    }
  }

  function handle_search_input() {
    popover_element?.showPopover();
  }
</script>

<div
  class="combobox__container"
  onfocusin={handle_component_focusin}
  onfocusout={handle_component_focusout}
>
  <input
    bind:this={search_input_element}
    bind:value={search_value}
    class={search_input_class}
    oninput={handle_search_input}
    onkeydown={handle_search_keydown}
    type="text"
  />
  <div
    bind:this={popover_element}
    class={popover_class ?? "combobox__popover"}
    popover="manual"
    role="listbox"
  >
    {#each completions as completion}
      <button
        aria-selected={value === completion}
        class="combobox__completion"
        onclick={() => handle_completion_click(completion)}
        role="option"
        type="button"
      >
        {completion}
      </button>
    {/each}
  </div>
</div>
