import type { Middleware, Placement } from "@floating-ui/dom";
import { flip, offset, shift } from "@floating-ui/dom";
import type { Accessor, JSX } from "solid-js";
import { createEffect, createSignal, createUniqueId, onCleanup, splitProps } from "solid-js";
import { createDisclosureState } from "../../primitives/create-disclosure-state";
import { createFloating } from "../../primitives/create-floating";
import { TooltipContent } from "./tooltip-content";
import {
  InternalTooltipContextProvider,
  TooltipContextProvider,
  useTooltipContext,
} from "./tooltip-context";
import type { InternalTooltipContextValue } from "./tooltip-context";
import { TooltipTrigger } from "./tooltip-trigger";
import type { TooltipRootProps } from "./tooltip.props";
export type { TooltipRootProps } from "./tooltip.props";

/**
 * Root component for Tooltip. Manages open state, delay timers,
 * floating positioning, and Escape key dismissal via context.
 */
export function TooltipRoot(props: TooltipRootProps): JSX.Element {
  const [local] = splitProps(props, [
    "open",
    "defaultOpen",
    "onOpenChange",
    "openDelay",
    "closeDelay",
    "children",
  ]);

  const triggerId = createUniqueId();
  const contentId = createUniqueId();

  const [triggerRef, setTriggerRef] = createSignal<HTMLElement | null>(null);
  const [contentRef, setContentRef] = createSignal<HTMLElement | null>(null);

  const disclosure = createDisclosureState({
    get open() {
      return local.open;
    },
    get defaultOpen() {
      return local.defaultOpen;
    },
    get onOpenChange() {
      return local.onOpenChange;
    },
  });

  const floating = createFloating({
    anchor: triggerRef,
    floating: contentRef,
    placement: (() => "top") as Accessor<Placement>,
    middleware: (() => [offset(8), flip(), shift({ padding: 8 })]) as Accessor<Middleware[]>,
    open: disclosure.isOpen,
  });

  // --- Delay timers ---

  let openTimer: ReturnType<typeof setTimeout> | undefined;
  let closeTimer: ReturnType<typeof setTimeout> | undefined;

  const cancelTimers = () => {
    if (openTimer !== undefined) {
      clearTimeout(openTimer);
      openTimer = undefined;
    }
    if (closeTimer !== undefined) {
      clearTimeout(closeTimer);
      closeTimer = undefined;
    }
  };

  const openDelayed = () => {
    cancelTimers();
    const delay = local.openDelay ?? 700;
    openTimer = setTimeout(() => {
      disclosure.open();
    }, delay);
  };

  const closeDelayed = () => {
    cancelTimers();
    const delay = local.closeDelay ?? 300;
    closeTimer = setTimeout(() => {
      disclosure.close();
    }, delay);
  };

  // --- Escape key listener ---

  createEffect(() => {
    if (!disclosure.isOpen()) return;

    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape") {
        cancelTimers();
        disclosure.close();
      }
    };

    document.addEventListener("keydown", handleKeyDown);
    onCleanup(() => document.removeEventListener("keydown", handleKeyDown));
  });

  // Clean up timers on disposal
  onCleanup(cancelTimers);

  const ctx: InternalTooltipContextValue = {
    isOpen: disclosure.isOpen,
    open: disclosure.open,
    close: disclosure.close,
    triggerRef,
    setTriggerRef,
    contentRef,
    setContentRef,
    contentId,
    triggerId,
    floatingStyle: floating.style,
    openDelayed,
    closeDelayed,
    cancelTimers,
  };

  return (
    <InternalTooltipContextProvider value={ctx}>
      <TooltipContextProvider value={{ open: disclosure.isOpen }}>
        {local.children}
      </TooltipContextProvider>
    </InternalTooltipContextProvider>
  );
}

/** Compound Tooltip component with all sub-components as static properties. */
export const Tooltip = Object.assign(TooltipRoot, {
  Trigger: TooltipTrigger,
  Content: TooltipContent,
  useContext: useTooltipContext,
});
