import { createApp, type App } from "vue";
import SuggestionDropdown from "@/components/SuggestionDropdown.vue";
import type { SuggestionItem } from "@/components/SuggestionDropdown.vue";
import type { SuggestionProps, SuggestionKeyDownProps } from "@tiptap/suggestion";

interface DropdownExposed {
  onKeyDown: (e: KeyboardEvent) => boolean;
}

export function createSuggestionRenderer() {
  let app: App | null = null;
  let el: HTMLElement | null = null;
  let componentRef: DropdownExposed | null = null;
  let commandFn: ((item: SuggestionItem) => void) | null = null;

  function mountDropdown(items: SuggestionItem[]) {
    if (!el) return;
    if (app) app.unmount();
    app = createApp(SuggestionDropdown, {
      items,
      command: (item: SuggestionItem) => commandFn?.(item),
    });
    const instance = app.mount(el);
    componentRef = instance as unknown as DropdownExposed;
  }

  return {
    onStart(props: SuggestionProps) {
      commandFn = (item: SuggestionItem) => props.command(item);

      el = document.createElement("div");
      el.style.position = "fixed";
      el.style.zIndex = "100";
      document.body.appendChild(el);

      mountDropdown(props.items as SuggestionItem[]);
      updatePosition(props);
    },

    onUpdate(props: SuggestionProps) {
      commandFn = (item: SuggestionItem) => props.command(item);
      mountDropdown(props.items as SuggestionItem[]);
      updatePosition(props);
    },

    onKeyDown(props: SuggestionKeyDownProps) {
      if (props.event.key === "Escape") {
        cleanup();
        return true;
      }
      return componentRef?.onKeyDown(props.event) ?? false;
    },

    onExit() {
      cleanup();
    },
  };

  function updatePosition(props: SuggestionProps) {
    if (!el || !props.clientRect) return;
    const rect = props.clientRect();
    if (!rect) return;
    el.style.top = rect.bottom + "px";
    el.style.left = rect.left + "px";
  }

  function cleanup() {
    if (app) {
      app.unmount();
      app = null;
    }
    if (el) {
      el.remove();
      el = null;
    }
    componentRef = null;
    commandFn = null;
  }
}
