"use client";

// ShortcutsRoot — global key listener + command palette + help overlay.
// Mount once in app/layout.tsx. Pages register actions via useAction().

import { useEffect, useState, useSyncExternalStore } from "react";
import { useRouter } from "next/navigation";
import { NAV } from "@/lib/nav";
import {
  shortcuts,
  eventToCombo,
  prettyCombo,
  shouldIgnore,
  type Action,
} from "@/lib/shortcuts";

export function ShortcutsRoot() {
  const router = useRouter();
  const [paletteOpen, setPaletteOpen] = useState(false);
  const [helpOpen, setHelpOpen] = useState(false);
  const [searchOpen, setSearchOpen] = useState(false);

  // Built-in actions: nav jumps, palette, search, help.
  useEffect(() => {
    const unsubs: Array<() => void> = [];

    // Nav jumps use mod+shift+N — browser owns plain mod+1..9 (tab switching).
    NAV.slice(0, 9).forEach((item, i) => {
      unsubs.push(
        shortcuts.register({
          id: `nav-${i}`,
          label: `Go to ${item.label}`,
          combo: `mod+shift+${i + 1}`,
          group: "Navigation",
          run: () => router.push(item.href),
        }),
      );
    });

    unsubs.push(
      // Palette uses mod+shift+p — browser owns plain mod+p (print).
      shortcuts.register({
        id: "palette",
        label: "Open command palette",
        combo: "mod+shift+p",
        group: "Help",
        run: () => setPaletteOpen(true),
      }),
      shortcuts.register({
        id: "search",
        label: "Search",
        combo: "mod+k",
        group: "Actions",
        run: () => setSearchOpen(true),
      }),
      shortcuts.register({
        id: "help",
        label: "Show keyboard shortcuts",
        combo: "?",
        group: "Help",
        run: () => setHelpOpen(true),
      }),
    );

    return () => { for (const u of unsubs) u(); };
  }, [router]);

  // Global key listener.
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      // Always allow Escape to close overlays even from inputs.
      if (e.key === "Escape") {
        if (paletteOpen) { setPaletteOpen(false); e.preventDefault(); return; }
        if (helpOpen)    { setHelpOpen(false);    e.preventDefault(); return; }
        if (searchOpen)  { setSearchOpen(false);  e.preventDefault(); return; }
      }

      if (shouldIgnore(e)) return;

      const combo = eventToCombo(e);
      const action = shortcuts.byCombo(combo);
      if (action) {
        e.preventDefault();
        void action.run();
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [paletteOpen, helpOpen, searchOpen]);

  return (
    <>
      {paletteOpen && <CommandPalette onClose={() => setPaletteOpen(false)} />}
      {helpOpen && <ShortcutsHelp onClose={() => setHelpOpen(false)} />}
      {searchOpen && <SearchModal onClose={() => setSearchOpen(false)} />}
    </>
  );
}

// ─── Command palette ──────────────────────────────────────────────────

function useShortcutsList(): Action[] {
  return useSyncExternalStore(
    (cb) => shortcuts.subscribe(cb),
    () => shortcuts.list(),
    () => shortcuts.list(),
  );
}

function CommandPalette({ onClose }: { onClose: () => void }) {
  const all = useShortcutsList();
  const [q, setQ] = useState("");
  const filtered = q
    ? all.filter((a) =>
        (a.label + " " + a.group + " " + (a.hint ?? "")).toLowerCase().includes(q.toLowerCase()),
      )
    : all;

  return (
    <Overlay onClose={onClose}>
      <div className="sc-palette" onClick={(e) => e.stopPropagation()}>
        <input
          autoFocus
          value={q}
          onChange={(e) => setQ(e.target.value)}
          placeholder="Type a command…"
          className="sc-palette-input"
        />
        <ul className="sc-palette-list">
          {filtered.length === 0 && <li className="sc-palette-empty">No matches</li>}
          {filtered.map((a) => (
            <li key={a.id}>
              <button
                className="sc-palette-item"
                onClick={() => { void a.run(); onClose(); }}
              >
                <span className="sc-palette-group">{a.group}</span>
                <span className="sc-palette-label">{a.label}</span>
                {a.combo && <kbd className="sc-kbd">{prettyCombo(a.combo)}</kbd>}
              </button>
            </li>
          ))}
        </ul>
      </div>
    </Overlay>
  );
}

// ─── Help overlay ─────────────────────────────────────────────────────

function ShortcutsHelp({ onClose }: { onClose: () => void }) {
  const all = useShortcutsList().filter((a) => a.combo);
  const groups: Record<string, Action[]> = {};
  for (const a of all) (groups[a.group] ||= []).push(a);

  return (
    <Overlay onClose={onClose}>
      <div className="sc-help" onClick={(e) => e.stopPropagation()}>
        <header className="sc-help-header">
          <h2>Keyboard shortcuts</h2>
          <button className="sc-help-close" onClick={onClose} aria-label="Close">×</button>
        </header>
        {Object.entries(groups).map(([group, actions]) => (
          <section key={group}>
            <h3>{group}</h3>
            <ul>
              {actions.map((a) => (
                <li key={a.id}>
                  <span>{a.label}</span>
                  <kbd className="sc-kbd">{prettyCombo(a.combo!)}</kbd>
                </li>
              ))}
            </ul>
          </section>
        ))}
      </div>
    </Overlay>
  );
}

// ─── Search modal (placeholder) ───────────────────────────────────────

function SearchModal({ onClose }: { onClose: () => void }) {
  return (
    <Overlay onClose={onClose}>
      <div className="sc-search" onClick={(e) => e.stopPropagation()}>
        <input autoFocus placeholder="Search…" className="sc-palette-input" />
        <p className="sc-search-hint">
          TODO: wire global search. Esc to close.
        </p>
      </div>
    </Overlay>
  );
}

function Overlay({ children, onClose }: { children: React.ReactNode; onClose: () => void }) {
  return (
    <div className="sc-overlay" onClick={onClose} role="dialog" aria-modal="true">
      {children}
    </div>
  );
}
