import { jsxs, jsx } from 'react/jsx-runtime';
import React__default, { useMemo, useState, useRef, useEffect, useCallback } from 'react';
import { commandPaletteTheme } from './CommandPalette.theme.js';
import { containerAnimations, overlayAnimations } from './CommandPalette.animations.js';
import { cn } from '../../../utils/cn.js';
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { CommandItem } from './CommandItem.js';
import { Overlay } from '../../effects/Overlay/Overlay.js';
import { ScrollArea } from '../ScrollArea/ScrollArea.js';
import '../ScrollArea/smooth/SmoothScrollEngine.js';

/**
 * Default filter function for commands
 */
const defaultFilterFunction = (command, searchValue) => {
    var _a, _b;
    const search = searchValue.toLowerCase();
    const labelMatch = command.label.toLowerCase().includes(search);
    const subtitleMatch = (_a = command.subtitle) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search);
    const keywordsMatch = (_b = command.keywords) === null || _b === void 0 ? void 0 : _b.some((keyword) => keyword.toLowerCase().includes(search));
    return labelMatch || subtitleMatch || keywordsMatch || false;
};
/**
 * Check if commands array is grouped
 */
const isGroupedCommands = (commands) => {
    return commands.length > 0 && "commands" in commands[0];
};
/**
 * Flatten grouped commands into a single array
 */
const flattenCommands = (commands) => {
    if (isGroupedCommands(commands)) {
        return commands.flatMap((group) => group.commands);
    }
    return commands;
};
/**
 * Group commands by their group property
 */
const groupCommandsByCategory = (commands) => {
    const grouped = {};
    commands.forEach((command) => {
        const groupKey = command.group || "Other";
        if (!grouped[groupKey]) {
            grouped[groupKey] = [];
        }
        grouped[groupKey].push(command);
    });
    return Object.entries(grouped).map(([label, groupCommands]) => ({
        id: label.toLowerCase().replace(/\s+/g, "-"),
        label,
        commands: groupCommands,
    }));
};
/**
 * CommandPalette Component
 *
 * A ⌘K style command palette for quick navigation and actions.
 *
 * @example
 * ```tsx
 * const [isOpen, setIsOpen] = useState(false);
 *
 * const commands = [
 *   {
 *     id: 'new-file',
 *     label: 'New File',
 *     contentStart: <DocumentPlusIcon />,
 *     shortcut: ['⌘', 'N'],
 *     onSelect: () => console.log('New file'),
 *   },
 * ];
 *
 * <CommandPalette
 *   isOpen={isOpen}
 *   onClose={() => setIsOpen(false)}
 *   commands={commands}
 * />
 * ```
 */
const CommandPalette = React__default.forwardRef(({ isOpen, onClose, commands = [], placeholder = "Type a command or search...", emptyMessage = "No results found.", maxHeight = "400px", className = "", overlayClassName = "", theme: themeOverrides, grouped = false, onSearchChange, filterFunction = defaultFilterFunction, closeOnOverlayClick = true, closeOnEsc = true, footer, footerClassName, }, ref) => {
    // Merge theme with overrides
    const theme = useMemo(() => ({ ...commandPaletteTheme, ...(themeOverrides || {}) }), [themeOverrides]);
    // State
    const [searchValue, setSearchValue] = useState("");
    const [highlightedIndex, setHighlightedIndex] = useState(0);
    // Refs
    const searchInputRef = useRef(null);
    const listContainerRef = useRef(null);
    // Flatten all commands for filtering
    const allCommands = useMemo(() => flattenCommands(commands), [commands]);
    // Filter commands based on search
    const filteredCommands = useMemo(() => {
        if (!searchValue.trim()) {
            return allCommands;
        }
        return allCommands.filter((command) => filterFunction(command, searchValue));
    }, [allCommands, searchValue, filterFunction]);
    // Group filtered commands if needed
    const displayCommands = useMemo(() => {
        if (grouped || isGroupedCommands(commands)) {
            return groupCommandsByCategory(filteredCommands);
        }
        return filteredCommands;
    }, [grouped, commands, filteredCommands]);
    // Get flat list of filtered commands for keyboard navigation
    const flatFilteredCommands = useMemo(() => {
        if (isGroupedCommands(displayCommands)) {
            return displayCommands.flatMap((group) => group.commands);
        }
        return displayCommands;
    }, [displayCommands]);
    // Reset highlighted index when search changes
    useEffect(() => {
        setHighlightedIndex(0);
    }, [searchValue]);
    // Focus search input when opened
    // Focus search input when opened
    useEffect(() => {
        if (isOpen && searchInputRef.current) {
            // Delay focus slightly to allow animation to start smoothly
            // This prevents layout thrashing during the initial composite frame
            const timer = setTimeout(() => {
                var _a;
                (_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
            }, 50);
            return () => clearTimeout(timer);
        }
    }, [isOpen]);
    // Reset search when closed
    useEffect(() => {
        if (!isOpen) {
            setSearchValue("");
            setHighlightedIndex(0);
        }
    }, [isOpen]);
    // Handle search change
    const handleSearchChange = useCallback((e) => {
        const value = e.target.value;
        setSearchValue(value);
        onSearchChange === null || onSearchChange === void 0 ? void 0 : onSearchChange(value);
    }, [onSearchChange]);
    // Handle command selection
    const handleSelectCommand = useCallback((command) => {
        if (command.disabled)
            return;
        command.onSelect();
        onClose();
    }, [onClose]);
    // Keep refs in sync for keydown handler to avoid re-attaching listener
    const flatFilteredCommandsRef = useRef(flatFilteredCommands);
    flatFilteredCommandsRef.current = flatFilteredCommands;
    const highlightedIndexRef = useRef(highlightedIndex);
    highlightedIndexRef.current = highlightedIndex;
    // Handle keyboard navigation (Arrow keys and Enter)
    // Note: Escape key is handled by Overlay component
    useEffect(() => {
        if (!isOpen)
            return;
        const handleKeyDown = (event) => {
            const cmds = flatFilteredCommandsRef.current;
            // Arrow keys navigation
            if (event.key === "ArrowDown") {
                event.preventDefault();
                setHighlightedIndex((prev) => prev >= cmds.length - 1 ? 0 : prev + 1);
            }
            else if (event.key === "ArrowUp") {
                event.preventDefault();
                setHighlightedIndex((prev) => prev <= 0 ? cmds.length - 1 : prev - 1);
            }
            else if (event.key === "Enter") {
                event.preventDefault();
                const highlightedCommand = cmds[highlightedIndexRef.current];
                if (highlightedCommand) {
                    handleSelectCommand(highlightedCommand);
                }
            }
        };
        document.addEventListener("keydown", handleKeyDown);
        return () => {
            document.removeEventListener("keydown", handleKeyDown);
        };
    }, [isOpen, handleSelectCommand]);
    // Scroll highlighted command into view
    useEffect(() => {
        if (listContainerRef.current) {
            const highlightedElement = listContainerRef.current.querySelector(`[data-command-index="${highlightedIndex}"]`);
            if (highlightedElement) {
                highlightedElement.scrollIntoView({
                    block: "nearest",
                    behavior: "smooth",
                });
            }
        }
    }, [highlightedIndex]);
    // Render commands list
    const renderCommandsList = () => {
        if (flatFilteredCommands.length === 0) {
            return jsx("div", { className: theme.emptyState, "aria-live": "polite", children: emptyMessage });
        }
        // If grouped, render with group labels
        if (isGroupedCommands(displayCommands)) {
            let commandIndex = 0;
            return displayCommands.map((group) => (jsxs("div", { className: "py-2", children: [jsx("div", { className: theme.groupLabel, children: group.label }), group.commands.map((command) => {
                        const element = (jsx(CommandItem, { command: command, index: commandIndex, isHighlighted: commandIndex === highlightedIndex, onSelect: handleSelectCommand, onMouseEnter: setHighlightedIndex, theme: theme }, command.id));
                        commandIndex++;
                        return element;
                    })] }, group.id)));
        }
        // Otherwise render flat list
        return displayCommands.map((command, index) => (jsx(CommandItem, { command: command, index: index, isHighlighted: index === highlightedIndex, onSelect: handleSelectCommand, onMouseEnter: setHighlightedIndex, theme: theme }, command.id)));
    };
    return (jsxs(Overlay, { ref: ref, isOpen: isOpen, onClose: onClose, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, position: "top", overlayClassName: overlayClassName, contentClassName: cn(theme.container, className), animations: {
            overlay: overlayAnimations,
            content: containerAnimations,
        }, children: [jsx("div", { className: theme.searchWrapper, children: jsxs("div", { className: "flex items-center gap-3", children: [jsx(MagnifyingGlassIcon, { className: "w-5 h-5 text-[var(--color-text-muted)]", strokeWidth: 2 }), jsx("input", { ref: searchInputRef, type: "text", className: theme.searchInput, placeholder: placeholder, value: searchValue, onChange: handleSearchChange, autoComplete: "off", autoCorrect: "off", spellCheck: false, "aria-label": "Search commands" })] }) }), jsx(ScrollArea, { ref: listContainerRef, type: "hover", className: "overscroll-contain px-1", style: {
                    maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
                }, children: jsx("div", { role: "listbox", "aria-label": "Commands", children: renderCommandsList() }) }), footer && (jsx("div", { className: cn(theme.footer, footerClassName), children: footer }))] }));
});
CommandPalette.displayName = "CommandPalette";

export { CommandPalette };
