import { useState, useEffect, useRef, useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { useVault } from "../App";
import { searchVault, listTemplates, createFromTemplate, exportNoteHtml, type SearchResult, type TemplateInfo } from "../lib/commands";

interface CommandItem {
    id: string;
    icon: string;
    label: string;
    hint?: string;
    action: () => void;
}

export function CommandPalette({ open, onClose }: { open: boolean; onClose: () => void }) {
    const { vaultPath, notes, navigateToNote, currentNote } = useVault();
    const navigate = useNavigate();
    const [query, setQuery] = useState("");
    const [selectedIndex, setSelectedIndex] = useState(0);
    const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
    const [templates, setTemplates] = useState<TemplateInfo[]>([]);
    const inputRef = useRef<HTMLInputElement>(null);
    const listRef = useRef<HTMLDivElement>(null);

    // Load templates when opened
    useEffect(() => {
        if (open && vaultPath) {
            listTemplates(vaultPath).then(setTemplates).catch(() => setTemplates([]));
        }
    }, [open, vaultPath]);

    // Focus input when opened
    useEffect(() => {
        if (open) {
            setQuery("");
            setSelectedIndex(0);
            setSearchResults([]);
            setTimeout(() => inputRef.current?.focus(), 50);
        }
    }, [open]);

    // Debounced search
    useEffect(() => {
        if (!query.trim() || query.length < 2) {
            setSearchResults([]);
            return;
        }

        const timer = setTimeout(async () => {
            try {
                const results = await searchVault(vaultPath, query);
                setSearchResults(results.slice(0, 10));
            } catch {
                setSearchResults([]);
            }
        }, 200);

        return () => clearTimeout(timer);
    }, [query, vaultPath]);

    // Build command list
    const commands: CommandItem[] = [];

    if (!query.trim()) {
        commands.push(
            { id: "daily", icon: "📅", label: "Open Daily Note", hint: "⌘D", action: () => { navigate("/daily"); onClose(); } },
            { id: "graph", icon: "🔮", label: "Graph View", hint: "⌘G", action: () => { navigate("/graph"); onClose(); } },
            { id: "new", icon: "✏️", label: "New Note", hint: "⌘N", action: () => { const name = prompt("Note name:"); if (name?.trim()) { navigateToNote(name.trim()); onClose(); } } },
        );

        // Template commands
        if (templates.length > 0) {
            for (const t of templates) {
                commands.push({
                    id: `template-${t.path}`,
                    icon: "📋",
                    label: `New from template: ${t.name}`,
                    hint: "_templates",
                    action: async () => {
                        const name = prompt(`Note name (from "${t.name}" template):`);
                        if (name?.trim()) {
                            try {
                                const path = await createFromTemplate(vaultPath, t.path, name.trim());
                                navigate(`/note/${encodeURIComponent(path)}`);
                                onClose();
                            } catch (e) {
                                console.error("Template creation failed:", e);
                            }
                        }
                    },
                });
            }
        }

        // v0.4 commands
        commands.push(
            { id: "calendar", icon: "📆", label: "Calendar View", action: () => { navigate("/calendar"); onClose(); } },
            { id: "theme", icon: "🎨", label: "Change Theme", hint: "⌘T", action: () => { onClose(); } },
        );

        if (currentNote) {
            commands.push({
                id: "export-html",
                icon: "📤",
                label: "Export as HTML",
                action: async () => {
                    try {
                        const html = await exportNoteHtml(vaultPath, currentNote);
                        const blob = new Blob([html], { type: "text/html" });
                        const url = URL.createObjectURL(blob);
                        const a = document.createElement("a");
                        a.href = url;
                        a.download = currentNote.replace(/\.md$/, ".html");
                        a.click();
                        URL.revokeObjectURL(url);
                        onClose();
                    } catch (e) {
                        console.error("Export failed:", e);
                    }
                },
            });
        }

        // v0.5 commands
        commands.push(
            { id: "kanban", icon: "📋", label: "Kanban Board", action: () => { navigate("/kanban"); onClose(); } },
            { id: "focus", icon: "🧘", label: "Focus Mode", hint: "⌘⇧F", action: () => { onClose(); } },
            { id: "search-replace", icon: "🔍", label: "Search & Replace", hint: "⌘H", action: () => { onClose(); } },
        );

        if (currentNote) {
            commands.push({
                id: "export-pdf",
                icon: "📄",
                label: "Export as PDF",
                action: () => {
                    onClose();
                    setTimeout(() => window.print(), 200);
                },
            });
        }

        // v0.6 commands
        commands.push(
            { id: "flashcards", icon: "🎴", label: "Flashcards", action: () => { navigate("/flashcards"); onClose(); } },
            { id: "custom-css", icon: "🎨", label: "Custom CSS", action: () => { onClose(); } },
            {
                id: "save-workspace", icon: "💾", label: "Save Workspace", action: () => {
                    const name = prompt("Workspace name:");
                    if (name?.trim()) { onClose(); }
                }
            },
        );

        // v0.7 commands
        commands.push(
            { id: "database", icon: "📊", label: "Database View", action: () => { navigate("/database"); onClose(); } },
            {
                id: "whiteboard", icon: "🎨", label: "New Whiteboard", action: () => {
                    const name = prompt("Canvas name:");
                    if (name?.trim()) { navigate(`/whiteboard/${encodeURIComponent(name.trim())}`); onClose(); }
                }
            },
            { id: "git-sync", icon: "🔀", label: "Git Sync", action: () => { onClose(); } },
        );

        // v0.8 commands
        commands.push(
            { id: "timeline", icon: "📅", label: "Timeline", action: () => { navigate("/timeline"); onClose(); } },
            {
                id: "random-note", icon: "🎲", label: "Random Note", action: async () => {
                    try {
                        const { randomNote } = await import("../lib/commands");
                        const name = await randomNote(vaultPath);
                        navigate(`/note/${encodeURIComponent(name)}`);
                    } catch { }
                    onClose();
                }
            },
        );

        // v0.9 commands
        commands.push(
            { id: "analytics", icon: "📊", label: "Graph Analytics", action: () => { navigate("/analytics"); onClose(); } },
            { id: "import-export", icon: "📦", label: "Import / Export", action: () => { onClose(); } },
            { id: "shortcuts", icon: "⌨️", label: "Keyboard Shortcuts", action: () => { onClose(); } },
        );
    }

    // Note matches
    const flatNotes = flattenNoteNames(notes);
    const queryLower = query.toLowerCase();
    if (query.trim()) {
        const nameMatches = flatNotes
            .filter(n => n.name.toLowerCase().includes(queryLower))
            .slice(0, 5);

        for (const note of nameMatches) {
            commands.push({
                id: `note-${note.path}`,
                icon: "📄",
                label: note.name,
                hint: note.path,
                action: () => { navigate(`/note/${encodeURIComponent(note.path)}`); onClose(); },
            });
        }

        // Content search results
        for (const result of searchResults) {
            // Don't duplicate filename matches
            if (commands.some(c => c.id === `note-${result.path}`)) continue;
            commands.push({
                id: `search-${result.path}`,
                icon: "🔍",
                label: result.name,
                hint: result.context.substring(0, 80),
                action: () => { navigate(`/note/${encodeURIComponent(result.path)}`); onClose(); },
            });
        }
    }

    // Clamp selection
    const maxIndex = Math.max(0, commands.length - 1);
    const safeIndex = Math.min(selectedIndex, maxIndex);

    const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
        if (e.key === "ArrowDown") {
            e.preventDefault();
            setSelectedIndex(i => Math.min(i + 1, maxIndex));
        } else if (e.key === "ArrowUp") {
            e.preventDefault();
            setSelectedIndex(i => Math.max(i - 1, 0));
        } else if (e.key === "Enter") {
            e.preventDefault();
            commands[safeIndex]?.action();
        } else if (e.key === "Escape") {
            e.preventDefault();
            onClose();
        }
    }, [commands, safeIndex, maxIndex, onClose]);

    // Scroll selected item into view
    useEffect(() => {
        const list = listRef.current;
        if (!list) return;
        const item = list.children[safeIndex] as HTMLElement | undefined;
        item?.scrollIntoView({ block: "nearest" });
    }, [safeIndex]);

    if (!open) return null;

    return (
        <div className="cmd-backdrop" onClick={onClose}>
            <div className="cmd-palette" onClick={e => e.stopPropagation()} onKeyDown={handleKeyDown}>
                {/* Search input */}
                <div className="cmd-input-wrap">
                    <svg className="cmd-input-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                        <circle cx="11" cy="11" r="8" />
                        <path d="m21 21-4.35-4.35" />
                    </svg>
                    <input
                        ref={inputRef}
                        className="cmd-input"
                        type="text"
                        placeholder="Search notes, commands..."
                        value={query}
                        onChange={e => { setQuery(e.target.value); setSelectedIndex(0); }}
                    />
                    <kbd className="cmd-kbd">ESC</kbd>
                </div>

                {/* Results */}
                <div className="cmd-list" ref={listRef}>
                    {commands.length === 0 && query.trim() && (
                        <div className="cmd-empty">No results for "{query}"</div>
                    )}
                    {commands.map((cmd, i) => (
                        <button
                            key={cmd.id}
                            className={`cmd-item ${i === safeIndex ? "selected" : ""}`}
                            onClick={cmd.action}
                            onMouseEnter={() => setSelectedIndex(i)}
                        >
                            <span className="cmd-item-icon">{cmd.icon}</span>
                            <span className="cmd-item-label">{cmd.label}</span>
                            {cmd.hint && <span className="cmd-item-hint">{cmd.hint}</span>}
                        </button>
                    ))}
                </div>

                {/* Footer */}
                <div className="cmd-footer">
                    <span>↑↓ navigate</span>
                    <span>↵ select</span>
                    <span>esc close</span>
                </div>
            </div>
        </div>
    );
}

/* ── Helpers ────────────────────────────────────────────────── */
function flattenNoteNames(
    entries: { name: string; path: string; is_dir: boolean; children?: any[] }[]
): { name: string; path: string }[] {
    const result: { name: string; path: string }[] = [];
    for (const entry of entries) {
        if (entry.is_dir && entry.children) {
            result.push(...flattenNoteNames(entry.children));
        } else if (!entry.is_dir) {
            result.push({ name: entry.name, path: entry.path });
        }
    }
    return result;
}
