import {
    createContext,
    useContext,
    ReactNode,
    useCallback,
    useEffect,
    useMemo,
    useState,
} from "react";
import { ShortcutDefinition } from "../hooks/useKeyboardShortcuts";

export interface ShortcutCategory {
    name: string;
    shortcuts: { [id: string]: ShortcutDefinition };
}

interface ShortcutContextValue {
    categories: ShortcutCategory[];
    registerCategory: (category: ShortcutCategory) => void;
    unregisterCategory: (categoryName: string) => void;
    showHelp: boolean;
    setShowHelp: (show: boolean) => void;
}

const ShortcutContext = createContext<ShortcutContextValue | undefined>(undefined);

export function ShortcutProvider({ children }: { children: ReactNode }) {
    const [categories, setCategories] = useState<ShortcutCategory[]>([]);
    const [showHelp, setShowHelp] = useState(false);

    useEffect(() => {
        const handler = (e: KeyboardEvent) => {
            const target = e.target as HTMLElement | null;
            const isEditableTarget =
                !!target &&
                (target.tagName === "INPUT" ||
                    target.tagName === "TEXTAREA" ||
                    target.tagName === "SELECT" ||
                    target.isContentEditable);

            // Don't steal regular typing inside form fields.
            // Allow modified shortcuts (cmd/ctrl/alt) to keep working.
            if (isEditableTarget && !e.metaKey && !e.ctrlKey && !e.altKey) {
                return;
            }

            if (showHelp && e.key !== "Escape") return;

            for (const category of categories) {
                for (const shortcut of Object.values(category.shortcuts)) {
                    if (shortcut.enabled === false) continue;

                    if (!!shortcut.meta !== e.metaKey) continue;
                    if (!!shortcut.ctrl !== e.ctrlKey) continue;
                    if (!!shortcut.alt !== e.altKey) continue;
                    if (!!shortcut.shift !== e.shiftKey) continue;

                    const keyMatches =
                        e.key === shortcut.key ||
                        e.key.toLowerCase() === shortcut.key.toLowerCase();

                    if (!keyMatches) continue;

                    e.preventDefault();
                    e.stopPropagation();
                    shortcut.handler();
                    return;
                }
            }
        };

        window.addEventListener("keydown", handler);
        return () => window.removeEventListener("keydown", handler);
    }, [categories, showHelp]);

    const registerCategory = useCallback((category: ShortcutCategory) => {
        setCategories((prev) => {
            // Replace if exists, otherwise add
            const existing = prev.findIndex((c) => c.name === category.name);
            if (existing >= 0) {
                const updated = [...prev];
                updated[existing] = category;
                return updated;
            }
            return [...prev, category];
        });
    }, []);

    const unregisterCategory = useCallback((categoryName: string) => {
        setCategories((prev) => prev.filter((c) => c.name !== categoryName));
    }, []);

    const value = useMemo(
        () => ({ categories, registerCategory, unregisterCategory, showHelp, setShowHelp }),
        [categories, registerCategory, unregisterCategory, showHelp]
    );

    return <ShortcutContext.Provider value={value}>{children}</ShortcutContext.Provider>;
}

export function useShortcutContext() {
    const context = useContext(ShortcutContext);
    if (!context) {
        throw new Error("useShortcutContext must be used within ShortcutProvider");
    }
    return context;
}
