<script lang="ts">
  import icon_cube_transparent from "../assets/heroicons/20/solid/cube-transparent.svg?raw";
  import icon_cube from "../assets/heroicons/20/solid/cube.svg?raw";
  import type { Datum } from "./datum.svelte";
  import {
    datum_from_editor_state,
    editor_state_from_datum,
    type EditorState,
  } from "./editor-state.svelte";
  import { type FieldInfo } from "./field.svelte";

  type Props = {
    /**
     * For use cases in which the user may select between multiple datum types,
     * such as when embedded in an expression editor, this array represents the
     * permissible set of field parameters.
     */
    assignable_fields?: ReadonlyArray<FieldInfo>;

    field_info: FieldInfo;

    on_change?(value?: Datum): void;

    value?: Datum;
  };

  let {
    assignable_fields = [],
    field_info = $bindable(),
    on_change,
    value = $bindable(),
  }: Props = $props();

  let editor_state = $state<EditorState | undefined>();
  let type_selector_menu_button_element = $state<
    HTMLButtonElement | undefined
  >();
  let type_selector_popover_element = $state<HTMLDivElement | undefined>();
  let text_input_element = $state<HTMLInputElement | undefined>();

  $effect(() => {
    if (value) {
      editor_state = editor_state_from_datum(value);
    }
  });

  export function focus() {
    text_input_element?.focus();
  }

  function handle_input() {
    if (!editor_state) {
      console.warn("preconditions for handle_input() not met");
      return;
    }
    value = datum_from_editor_state(
      editor_state,
      field_info.field.presentation,
    );
    console.log(value);
    on_change?.(value);
  }

  function handle_type_selector_menu_button_click() {
    type_selector_popover_element?.togglePopover();
  }

  function handle_type_selector_field_button_click(value: FieldInfo) {
    field_info = value;
    type_selector_popover_element?.hidePopover();
    type_selector_menu_button_element?.focus();
  }
</script>

<div
  class="datum-editor__container"
  class:datum-editor__container--incomplete={!value}
>
  {#if editor_state}
    {#if assignable_fields?.length > 0}
      <div class="datum-editor__type-selector">
        <button
          bind:this={type_selector_menu_button_element}
          class="datum-editor__type-selector-menu-button"
          onclick={handle_type_selector_menu_button_click}
          type="button"
        >
          {field_info.field.presentation.t}
        </button>
        <div
          bind:this={type_selector_popover_element}
          class="datum-editor__type-selector-popover"
          popover="auto"
        >
          {#each assignable_fields as assignable_field_info}
            <button
              onclick={() =>
                handle_type_selector_field_button_click(assignable_field_info)}
              type="button"
            >
              {assignable_field_info.field.presentation.t}
            </button>
          {/each}
        </div>
      </div>
    {/if}
    <button
      type="button"
      class="datum-editor__null-control"
      class:datum-editor__null-control--disabled={editor_state.text_value !==
        ""}
      disabled={editor_state.text_value !== ""}
      onclick={() => {
        if (!editor_state) {
          console.warn("null control onclick() preconditions not met");
          return;
        }
        editor_state.is_null = !editor_state.is_null;
        handle_input();
      }}
    >
      {#if editor_state.is_null}
        {@html icon_cube_transparent}
      {:else}
        {@html icon_cube}
      {/if}
    </button>
    {#if field_info.field.presentation.t === "Dropdown" || field_info.field.presentation.t === "Text" || field_info.field.presentation.t === "Uuid"}
      <input
        bind:this={text_input_element}
        value={editor_state.text_value}
        oninput={({ currentTarget }) => {
          if (!editor_state) {
            console.warn("text input oninput() preconditions not met");
            return;
          }
          editor_state.text_value = currentTarget.value;
          if (currentTarget.value !== "") {
            editor_state.is_null = false;
          }
          handle_input();
        }}
        class="datum-editor__text-input"
        type="text"
      />
    {:else if field_info.field.presentation.t === "Timestamp"}
      <input value={editor_state.date_value} type="date" />
      <input value={editor_state.time_value} type="time" />
    {/if}
    <div class="datum-editor__helpers" tabindex="-1">
      {#if field_info.field.presentation.t === "Dropdown"}
        <!-- TODO: This is an awkward way to implement a keyboard-navigable listbox. -->
        <menu class="datum-editor__dropdown-options">
          {#each field_info.field.presentation.c.options as dropdown_option}
            <!-- FIXME: validate or escape dropdown_option.color -->
            <li
              class={[
                "dropdown-option-badge",
                `dropdown-option-badge--${dropdown_option.color.toLocaleLowerCase("en-US")}`,
              ]}
              role="option"
              aria-selected={dropdown_option.value === value?.c}
            >
              <button
                class="datum-editor__dropdown-option-button"
                onclick={() => {
                  if (!editor_state || !text_input_element) {
                    console.warn(
                      "dropdown option onclick() preconditions not met",
                    );
                    return;
                  }
                  editor_state.text_value = dropdown_option.value;
                  editor_state.is_null = false;
                  text_input_element.focus();
                  handle_input();
                }}
                type="button"
              >
                {dropdown_option.value}
              </button>
            </li>
          {/each}
        </menu>
      {/if}
    </div>
  {/if}
</div>
