import React, { useEffect, useMemo, useState } from 'react';
import { Dialog } from '@/components/elements/dialog';
import { Button } from '@/components/elements/button/index';
import Input from '@/components/elements/Input';
import GreyRowBox from '@/components/elements/GreyRowBox';
import { shortcutFromEvent } from './keybindings';

export interface CommandPaletteCommand {
    id: string;
    label: string;
    description?: string;
    shortcut?: string;
    defaultShortcut?: string;
    disabled?: boolean;
    action: () => void;
}

interface Props {
    open: boolean;
    commands: CommandPaletteCommand[];
    onClose: () => void;
    onShortcutChange: (id: string, shortcut: string) => void;
    onShortcutReset: (id: string) => void;
    onResetAllShortcuts: () => void;
}

const cx = (...parts: Array<string | false | null | undefined>) => parts.filter(Boolean).join(' ');

const CommandPaletteDialog: React.FC<Props> = ({
    open,
    commands,
    onClose,
    onShortcutChange,
    onShortcutReset,
    onResetAllShortcuts,
}) => {
    const [query, setQuery] = useState('');
    const [bindingCommandId, setBindingCommandId] = useState<string | null>(null);

    useEffect(() => {
        if (!open) {
            setQuery('');
            setBindingCommandId(null);
        }
    }, [open]);

    const filteredCommands = useMemo(() => {
        const needle = query.trim().toLowerCase();
        if (!needle) return commands;

        return commands.filter((command) => (
            command.label.toLowerCase().includes(needle) ||
            command.description?.toLowerCase().includes(needle) ||
            command.shortcut?.toLowerCase().includes(needle) ||
            command.defaultShortcut?.toLowerCase().includes(needle)
        ));
    }, [commands, query]);

    const runCommand = (command: CommandPaletteCommand) => {
        if (command.disabled) return;
        onClose();
        command.action();
    };

    const firstEnabledCommand = filteredCommands.find((command) => !command.disabled);
    const shortcutOwner = (shortcut: string | undefined, commandId: string) => {
        if (!shortcut) return null;
        return commands.find((command) => command.id !== commandId && command.shortcut === shortcut) || null;
    };

    const handleShortcutCapture = (e: React.KeyboardEvent<HTMLButtonElement>, command: CommandPaletteCommand) => {
        e.preventDefault();
        e.stopPropagation();

        if (e.key === 'Escape') {
            setBindingCommandId(null);
            return;
        }

        const shortcut = shortcutFromEvent(e);
        if (!shortcut) return;

        onShortcutChange(command.id, shortcut);
        setBindingCommandId(null);
    };

    return (
        <Dialog open={open} onClose={onClose} title='Command Palette'>
            <div className='space-y-4'>
                <Input
                    value={query}
                    autoFocus
                    onChange={(e) => setQuery(e.currentTarget.value)}
                    onKeyDown={(e) => {
                        if (e.key === 'Enter' && firstEnabledCommand) {
                            e.preventDefault();
                            runCommand(firstEnabledCommand);
                        }
                    }}
                    placeholder='Search commands...'
                />

                {bindingCommandId && (
                    <GreyRowBox className='!items-center !justify-between gap-3 !px-4 !py-3' $hoverable={false}>
                        <div className='min-w-0'>
                            <div className='text-sm font-semibold text-neutral-100'>Press a shortcut</div>
                            <div className='mt-1 text-xs text-neutral-400'>Use Ctrl, Alt, Shift, or a function key. Esc cancels.</div>
                        </div>
                        <Button.Text type='button' size={Button.Sizes.Small} onClick={() => setBindingCommandId(null)}>
                            Cancel
                        </Button.Text>
                    </GreyRowBox>
                )}

                <GreyRowBox className='!flex-col !items-stretch !p-0 overflow-hidden' $hoverable={false}>
                    <div className='max-h-[420px] overflow-y-auto'>
                        {filteredCommands.length === 0 ? (
                            <div className='px-4 py-6 text-sm text-neutral-400'>No commands found.</div>
                        ) : (
                            filteredCommands.map((command) => {
                                const isBinding = bindingCommandId === command.id;
                                const conflict = shortcutOwner(command.shortcut, command.id);
                                const hasCustomShortcut = !!command.defaultShortcut && command.shortcut !== command.defaultShortcut;

                                return (
                                    <div
                                        key={command.id}
                                        className='border-b border-neutral-700 px-4 py-3 last:border-b-0'
                                    >
                                        <div className='flex flex-col gap-3 md:flex-row md:items-center'>
                                            <button
                                                type='button'
                                                disabled={command.disabled}
                                                className={cx(
                                                    'min-w-0 flex-1 text-left focus:outline-none',
                                                    command.disabled ? 'cursor-not-allowed text-neutral-500' : 'text-neutral-200'
                                                )}
                                                onClick={() => runCommand(command)}
                                            >
                                                <div className='truncate text-sm font-semibold'>{command.label}</div>
                                                {command.description && (
                                                    <div className='mt-1 truncate text-xs text-neutral-400'>{command.description}</div>
                                                )}
                                            </button>
                                            <div className='flex shrink-0 flex-wrap items-center gap-2'>
                                                <span
                                                    className={cx(
                                                        'rounded border px-2 py-1 text-xs',
                                                        command.shortcut
                                                            ? 'border-neutral-600 text-neutral-200'
                                                            : 'border-neutral-700 text-neutral-500'
                                                    )}
                                                >
                                                    {command.shortcut || 'Unbound'}
                                                </span>
                                                {isBinding ? (
                                                    <Button.Text
                                                        type='button'
                                                        autoFocus
                                                        size={Button.Sizes.Small}
                                                        className='border-neutral-500 text-neutral-100'
                                                        onKeyDown={(e) => handleShortcutCapture(e, command)}
                                                    >
                                                        Press keys
                                                    </Button.Text>
                                                ) : (
                                                    <Button.Text
                                                        type='button'
                                                        size={Button.Sizes.Small}
                                                        onClick={() => setBindingCommandId(command.id)}
                                                    >
                                                        Rebind
                                                    </Button.Text>
                                                )}
                                                <Button.Text
                                                    type='button'
                                                    size={Button.Sizes.Small}
                                                    disabled={!hasCustomShortcut}
                                                    onClick={() => onShortcutReset(command.id)}
                                                >
                                                    Reset
                                                </Button.Text>
                                            </div>
                                        </div>
                                        {conflict && (
                                            <div className='mt-2 text-xs text-yellow-300'>
                                                Also used by {conflict.label}.
                                            </div>
                                        )}
                                    </div>
                                );
                            })
                        )}
                    </div>
                </GreyRowBox>
            </div>
            <Dialog.Footer>
                <Button.Text onClick={onResetAllShortcuts}>Reset Keybinds</Button.Text>
                <Button.Text onClick={onClose}>Close</Button.Text>
            </Dialog.Footer>
        </Dialog>
    );
};

export default CommandPaletteDialog;
