"use client";
import {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
  useSyncExternalStore,
} from "react";
import { useRouter } from "next/navigation";

import {
  filterCommands,
  globalCommands,
  moveHighlight,
  projectCommands,
  type Command,
  type ToolCommandInfo,
} from "@/lib/command/palette";
import { handleTabTrap } from "@/lib/a11y/focusTrap";
import { api } from "@/lib/api/client";
import { useBodyScrollLock } from "@/lib/ui/useBodyScrollLock";
import { focusRing, overlayScrim } from "@/lib/ui/variants";

// 命令面板开关的极简外部 store：⌘K 与可见入口（顶栏按钮 / 移动抽屉）共享同一开态。
// 用 useSyncExternalStore 订阅，避免把 open 提升到 RootLayout context 造成全树重渲染。
let paletteOpen = false;
const paletteListeners = new Set<() => void>();

function emitPalette(): void {
  for (const listener of paletteListeners) listener();
}

export function setCommandPaletteOpen(next: boolean): void {
  if (paletteOpen === next) return;
  paletteOpen = next;
  emitPalette();
}

export function openCommandPalette(): void {
  setCommandPaletteOpen(true);
}

export function toggleCommandPalette(): void {
  setCommandPaletteOpen(!paletteOpen);
}

function subscribePalette(callback: () => void): () => void {
  paletteListeners.add(callback);
  return () => paletteListeners.delete(callback);
}

function getPaletteSnapshot(): boolean {
  return paletteOpen;
}

// SSR 快照恒为 false（命令面板永不在服务端渲染开态），避免水合不一致。
export function useCommandPaletteOpen(): boolean {
  return useSyncExternalStore(
    subscribePalette,
    getPaletteSnapshot,
    () => false,
  );
}

const LIST_ID = "command-list";
const optionId = (cmd: Command): string => `command-option-${cmd.id}`;

// 从 pathname 抽取当前 projectId（/projects/<id>/...）。
function projectIdFromPath(pathname: string): string | null {
  const m = pathname.match(/^\/projects\/([^/]+)/);
  return m?.[1] ?? null;
}

interface CommandPaletteProps {
  pathname: string;
}

// 命令面板（⌘K，UX §7）：键盘触发的快速导航/动作。
// WAI-ARIA combobox/listbox：input role=combobox（aria-expanded/controls/activedescendant），
// 列表 role=listbox，每项稳定 id + role=option。焦点管理：打开聚焦输入框、关闭归还触发元素。
export function CommandPalette({ pathname }: CommandPaletteProps) {
  const router = useRouter();
  const open = useCommandPaletteOpen();
  const [query, setQuery] = useState("");
  const [highlight, setHighlight] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const dialogRef = useRef<HTMLDivElement>(null);
  // 打开前的焦点元素：关闭时归还焦点（WCAG 2.4.3）。
  const restoreFocusRef = useRef<HTMLElement | null>(null);
  // 工具箱生成器（命令面板发现性）：首次打开惰性拉取一次，失败静默降级为空。
  const [tools, setTools] = useState<ToolCommandInfo[]>([]);
  const toolsLoadedRef = useRef(false);

  const projectId = projectIdFromPath(pathname);
  const commands = useMemo<Command[]>(
    () =>
      projectId
        ? [...projectCommands(projectId, tools), ...globalCommands()]
        : globalCommands(),
    [projectId, tools],
  );
  const results = useMemo(
    () => filterCommands(commands, query),
    [commands, query],
  );

  const close = useCallback((): void => {
    setCommandPaletteOpen(false);
    setQuery("");
    setHighlight(0);
  }, []);

  const run = useCallback(
    (cmd: Command | undefined): void => {
      if (!cmd) return;
      close();
      if (cmd.href) router.push(cmd.href);
    },
    [close, router],
  );

  useBodyScrollLock(open);

  // ⌘K / Ctrl+K 全局开关。
  useEffect(() => {
    const onKey = (e: KeyboardEvent): void => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        toggleCommandPalette();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  // 打开时记住先前焦点并聚焦输入框；关闭后把焦点归还触发元素。
  useEffect(() => {
    if (open) {
      restoreFocusRef.current = document.activeElement as HTMLElement | null;
      inputRef.current?.focus();
      return;
    }
    restoreFocusRef.current?.focus();
    restoreFocusRef.current = null;
  }, [open]);

  // 首次打开（项目内）惰性拉工具箱生成器列表，供生成 action-gen-<key> 命令。
  useEffect(() => {
    if (!open || !projectId || toolsLoadedRef.current) return;
    toolsLoadedRef.current = true;
    let cancelled = false;
    void (async () => {
      try {
        const { data } = await api.GET("/skills/toolbox");
        if (cancelled || !data?.tools) return;
        setTools(
          data.tools
            .filter((t) => !t.is_legacy)
            .map((t) => ({ key: t.key, title: t.title, genre: t.genre })),
        );
      } catch {
        // 静默降级：命令面板照常工作，仅缺生成器动作。
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [open, projectId]);
  useEffect(() => {
    setHighlight(0);
  }, [query]);

  if (!open) return null;

  const activeCmd = results[highlight];

  const onInputKey = (e: React.KeyboardEvent): void => {
    if (e.key === "Escape") {
      e.preventDefault();
      close();
    } else if (e.key === "ArrowDown") {
      e.preventDefault();
      setHighlight((h) => moveHighlight(h, 1, results.length));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setHighlight((h) => moveHighlight(h, -1, results.length));
    } else if (e.key === "Enter") {
      e.preventDefault();
      run(results[highlight]);
    }
  };

  return (
    <div
      className={`${overlayScrim} flex items-start justify-center pt-[15vh] motion-safe:transition-opacity`}
      onClick={close}
    >
      <div
        ref={dialogRef}
        role="dialog"
        aria-modal="true"
        aria-label="命令面板"
        className="w-full max-w-lg overflow-hidden rounded border border-line bg-panel shadow-paper"
        onClick={(e) => e.stopPropagation()}
        onKeyDown={(e) => {
          // focus trap：Tab/Shift+Tab 在对话框内循环，不逃逸到背景（WCAG 2.1.2）。
          if (dialogRef.current) handleTabTrap(dialogRef.current, e);
        }}
      >
        <input
          ref={inputRef}
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          onKeyDown={onInputKey}
          placeholder="搜索命令或页面…（写本章 / 审稿 / 生成角色 / 跳转伏笔 / 搜设定）"
          role="combobox"
          aria-label="命令搜索"
          aria-expanded={true}
          aria-controls={LIST_ID}
          aria-activedescendant={activeCmd ? optionId(activeCmd) : undefined}
          aria-autocomplete="list"
          className={`w-full border-b border-line bg-bg px-4 py-3 text-sm text-ink ${focusRing}`}
        />
        <ul
          id={LIST_ID}
          role="listbox"
          aria-label="命令列表"
          className="max-h-80 overflow-auto py-1 overscroll-contain"
        >
          {results.length === 0 ? (
            <li className="px-4 py-3 text-sm text-ink-soft">无匹配命令</li>
          ) : (
            results.map((cmd, i) => (
              <li
                key={cmd.id}
                id={optionId(cmd)}
                role="option"
                aria-selected={i === highlight}
                onMouseEnter={() => setHighlight(i)}
                onClick={() => run(cmd)}
                className={`flex cursor-pointer items-center justify-between px-4 py-2 text-sm ${
                  i === highlight
                    ? "bg-[var(--color-cinnabar-wash)] text-cinnabar"
                    : "text-ink"
                }`}
              >
                <span>{cmd.title}</span>
                <span className="text-xs text-ink-soft">{cmd.group}</span>
              </li>
            ))
          )}
        </ul>
      </div>
    </div>
  );
}
