import { useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate } from '@tanstack/react-router';
import Fuse from 'fuse.js';
import { useUiStore } from '@/stores/uiStore';
import { useActiveCampaign } from '@/features/campaigns/hooks';
import { useCharacters } from '@/features/characters/hooks';
import { useNotes, useNpcs, useQuests } from '@/features/world/hooks';
import { cn } from '@/lib/cn';

interface Command {
  id: string;
  label: string;
  hint?: string;
  run: () => void;
}

const NAV: { label: string; to: string }[] = [
  { label: 'Campaigns', to: '/' },
  { label: 'Dashboard', to: '/dashboard' },
  { label: 'Assistant', to: '/assistant' },
  { label: 'Characters', to: '/characters' },
  { label: 'Combat', to: '/combat' },
  { label: 'Dice', to: '/dice' },
  { label: 'Compendium', to: '/compendium' },
  { label: 'Notes', to: '/notes' },
  { label: 'NPCs', to: '/npcs' },
  { label: 'Quests', to: '/quests' },
  { label: 'Maps', to: '/maps' },
  { label: 'Homebrew', to: '/homebrew' },
  { label: 'Player View', to: '/play' },
  { label: 'Settings', to: '/settings' },
];

export function CommandPalette({ onClose }: { onClose: () => void }) {
  const navigate = useNavigate();
  const toggleTheme = useUiStore((s) => s.toggleTheme);
  const campaign = useActiveCampaign();
  const cid = campaign?.id ?? '';
  const characters = useCharacters(cid);
  const notes = useNotes(cid);
  const npcs = useNpcs(cid);
  const quests = useQuests(cid);

  const [q, setQ] = useState('');
  const [idx, setIdx] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => { inputRef.current?.focus(); }, []);

  const go = (to: string, params?: Record<string, string>) => () => {
    void navigate(params ? { to, params } : { to });
    onClose();
  };

  const commands = useMemo<Command[]>(() => {
    const list: Command[] = NAV.map((n) => ({ id: `nav:${n.to}`, label: n.label, hint: 'Go', run: go(n.to) }));
    list.push({ id: 'act:theme', label: 'Toggle theme', hint: 'Action', run: () => { toggleTheme(); onClose(); } });
    for (const c of characters) list.push({ id: `char:${c.id}`, label: c.name, hint: 'Character', run: go('/characters/$characterId', { characterId: c.id }) });
    for (const n of notes) list.push({ id: `note:${n.id}`, label: n.title, hint: 'Note', run: go('/notes') });
    for (const n of npcs) list.push({ id: `npc:${n.id}`, label: n.name, hint: 'NPC', run: go('/npcs') });
    for (const qu of quests) list.push({ id: `quest:${qu.id}`, label: qu.title, hint: 'Quest', run: go('/quests') });
    return list;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [characters, notes, npcs, quests, toggleTheme]);

  const fuse = useMemo(() => new Fuse(commands, { keys: ['label'], threshold: 0.4 }), [commands]);
  const results = useMemo(() => (q.trim() ? fuse.search(q.trim()).map((r) => r.item) : commands).slice(0, 50), [q, fuse, commands]);
  const clampedIdx = Math.min(idx, Math.max(0, results.length - 1));

  const onKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'ArrowDown') { e.preventDefault(); setIdx((i) => Math.min(results.length - 1, i + 1)); }
    else if (e.key === 'ArrowUp') { e.preventDefault(); setIdx((i) => Math.max(0, i - 1)); }
    else if (e.key === 'Enter') { e.preventDefault(); results[clampedIdx]?.run(); }
    else if (e.key === 'Escape') { e.preventDefault(); onClose(); }
  };

  return (
    <div className="fixed inset-0 z-50 flex items-start justify-center p-4 pt-24" role="dialog" aria-modal aria-label="Command palette">
      <div className="absolute inset-0 bg-black/50 backdrop-blur-sm" onClick={onClose} aria-hidden />
      <div className="relative w-full max-w-lg overflow-hidden rounded-lg border border-line bg-panel shadow-2xl">
        <input
          ref={inputRef}
          value={q}
          onChange={(e) => { setQ(e.target.value); setIdx(0); }}
          onKeyDown={onKeyDown}
          placeholder="Search pages, characters, notes…"
          aria-label="Command search"
          className="w-full border-b border-line bg-transparent px-4 py-3 text-sm text-ink placeholder:text-muted focus:outline-none"
        />
        <ul className="max-h-80 overflow-auto py-1">
          {results.length === 0 ? (
            <li className="px-4 py-3 text-sm text-muted">No matches.</li>
          ) : (
            results.map((c, i) => (
              <li key={c.id}>
                <button
                  onMouseEnter={() => setIdx(i)}
                  onClick={() => c.run()}
                  className={cn('flex w-full items-center justify-between px-4 py-2 text-left text-sm', i === clampedIdx ? 'bg-elevated text-ink' : 'text-muted')}
                >
                  <span className="truncate">{c.label}</span>
                  {c.hint && <span className="shrink-0 text-xs text-muted">{c.hint}</span>}
                </button>
              </li>
            ))
          )}
        </ul>
      </div>
    </div>
  );
}
