use std::sync::LazyLock;

use crate::app::App;
use crate::commands::AppCommand;
use crate::page::Page;
use crate::state::Modal;

pub enum PaletteAction {
    Resolve(fn(&App) -> Option<AppCommand>),
    Save,
    Load,
    TogglePlaying,
    MuteToggle,
    SoloToggle,
    ClearMutes,
    ClearSolos,
    Hush,
    Panic,
    TestTone,
}

pub struct CommandEntry {
    pub name: &'static str,
    pub description: &'static str,
    pub category: &'static str,
    pub keybinding: &'static str,
    pub pages: &'static [Page],
    pub normal_mode: bool,
    pub action: Option<PaletteAction>,
}

const CATEGORY_ORDER: &[&str] = &[
    "Project",
    "Playback",
    "Navigation",
    "Editing",
    "Pattern",
    "Bank",
    "Clipboard",
    "Mute/Solo",
    "Audio",
    "Display",
    "Prelude",
    "Script",
    "Help",
];

pub fn category_index(cat: &str) -> usize {
    CATEGORY_ORDER.iter().position(|&c| c == cat).unwrap_or(usize::MAX)
}

pub static COMMANDS: LazyLock<Vec<CommandEntry>> = LazyLock::new(|| {
    use Page::*;
    vec![
        // === Project ===
        CommandEntry {
            name: "Save",
            description: "Save project",
            category: "Project",
            keybinding: "s",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Save),
        },
        CommandEntry {
            name: "Load",
            description: "Load project",
            category: "Project",
            keybinding: "l",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Load),
        },
        CommandEntry {
            name: "Quit",
            description: "Quit application",
            category: "Project",
            keybinding: "q",
            pages: &[],
            normal_mode: true,
            action: Some(PaletteAction::Resolve(|_| {
                Some(AppCommand::OpenModal(Modal::Confirm {
                    action: crate::state::ConfirmAction::Quit,
                    selected: false,
                }))
            })),
        },

        // === Playback ===
        CommandEntry {
            name: "Toggle Playback",
            description: "Start or stop the sequencer",
            category: "Playback",
            keybinding: "Space",
            pages: &[],
            normal_mode: true,
            action: Some(PaletteAction::TogglePlaying),
        },
        CommandEntry {
            name: "Tempo Up",
            description: "Increase tempo",
            category: "Playback",
            keybinding: "+",
            pages: &[Main],
            normal_mode: true,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::TempoUp))),
        },
        CommandEntry {
            name: "Tempo Down",
            description: "Decrease tempo",
            category: "Playback",
            keybinding: "-",
            pages: &[Main],
            normal_mode: true,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::TempoDown))),
        },
        CommandEntry {
            name: "Set Tempo",
            description: "Open tempo input",
            category: "Playback",
            keybinding: "T",
            pages: &[Main],
            normal_mode: true,
            action: Some(PaletteAction::Resolve(|_| {
                Some(AppCommand::OpenModal(Modal::SetTempo(String::new())))
            })),
        },

        // === Navigation ===
        CommandEntry {
            name: "Go to Dict",
            description: "Open dictionary view",
            category: "Navigation",
            keybinding: "F1",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Dict)))),
        },
        CommandEntry {
            name: "Go to Patterns",
            description: "Open patterns view",
            category: "Navigation",
            keybinding: "F2",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Patterns)))),
        },
        CommandEntry {
            name: "Go to Options",
            description: "Open options view",
            category: "Navigation",
            keybinding: "F3",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Options)))),
        },
        CommandEntry {
            name: "Go to Help",
            description: "Open help view",
            category: "Navigation",
            keybinding: "F4",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Help)))),
        },
        CommandEntry {
            name: "Go to Sequencer",
            description: "Open sequencer view",
            category: "Navigation",
            keybinding: "F5",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Main)))),
        },
        CommandEntry {
            name: "Go to Engine",
            description: "Open engine view",
            category: "Navigation",
            keybinding: "F6",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Engine)))),
        },
        CommandEntry {
            name: "Go to Script",
            description: "Open script view",
            category: "Navigation",
            keybinding: "F11",
            pages: &[],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::GoToPage(Script)))),
        },

        // === Editing ===
        CommandEntry {
            name: "Toggle Steps",
            description: "Toggle selected steps on/off",
            category: "Editing",
            keybinding: "t",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleSteps))),
        },
        CommandEntry {
            name: "Edit Step",
            description: "Open step editor",
            category: "Editing",
            keybinding: "Enter",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::OpenModal(Modal::Editor)))),
        },
        CommandEntry {
            name: "Rename Step",
            description: "Rename current step",
            category: "Editing",
            keybinding: "r",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern, step) = (
                    app.editor_ctx.bank,
                    app.editor_ctx.pattern,
                    app.editor_ctx.step,
                );
                let current_name = app
                    .current_edit_pattern()
                    .step(step)
                    .and_then(|s| s.name.clone())
                    .unwrap_or_default();
                Some(AppCommand::OpenModal(Modal::Rename {
                    target: crate::state::RenameTarget::Step { bank, pattern, step },
                    name: current_name,
                }))
            })),
        },
        CommandEntry {
            name: "Euclidean Distribution",
            description: "Distribute linked steps using Euclidean rhythm",
            category: "Editing",
            keybinding: "e",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern, step) = (
                    app.editor_ctx.bank,
                    app.editor_ctx.pattern,
                    app.editor_ctx.step,
                );
                let pattern_len = app.current_edit_pattern().length;
                let default_steps = pattern_len.min(32);
                let default_pulses = (default_steps / 2).max(1).min(default_steps);
                Some(AppCommand::OpenModal(Modal::EuclideanDistribution {
                    bank,
                    pattern,
                    source_step: step,
                    field: crate::state::EuclideanField::Pulses,
                    pulses: default_pulses.to_string(),
                    steps: default_steps.to_string(),
                    rotation: "0".to_string(),
                }))
            })),
        },
        CommandEntry {
            name: "Undo",
            description: "Undo last action",
            category: "Editing",
            keybinding: "Ctrl+Z",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::Undo))),
        },
        CommandEntry {
            name: "Redo",
            description: "Redo last action",
            category: "Editing",
            keybinding: "Ctrl+Shift+Z",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::Redo))),
        },

        // === Pattern ===
        CommandEntry {
            name: "Length Increase",
            description: "Increase pattern length",
            category: "Pattern",
            keybinding: ">",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::LengthIncrease))),
        },
        CommandEntry {
            name: "Length Decrease",
            description: "Decrease pattern length",
            category: "Pattern",
            keybinding: "<",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::LengthDecrease))),
        },
        CommandEntry {
            name: "Speed Increase",
            description: "Increase pattern speed",
            category: "Pattern",
            keybinding: "]",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::SpeedIncrease))),
        },
        CommandEntry {
            name: "Speed Decrease",
            description: "Decrease pattern speed",
            category: "Pattern",
            keybinding: "[",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::SpeedDecrease))),
        },
        CommandEntry {
            name: "Set Length",
            description: "Open length input",
            category: "Pattern",
            keybinding: "L",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| {
                Some(AppCommand::OpenPatternModal(crate::state::PatternField::Length))
            })),
        },
        CommandEntry {
            name: "Set Speed",
            description: "Open speed input",
            category: "Pattern",
            keybinding: "S",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| {
                Some(AppCommand::OpenPatternModal(crate::state::PatternField::Speed))
            })),
        },
        CommandEntry {
            name: "Copy Pattern",
            description: "Copy current pattern",
            category: "Pattern",
            keybinding: "Ctrl+C",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                Some(AppCommand::CopyPattern { bank, pattern })
            })),
        },
        CommandEntry {
            name: "Paste Pattern",
            description: "Paste pattern from clipboard",
            category: "Pattern",
            keybinding: "Ctrl+V",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                if app.copied_patterns.is_some() {
                    let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                    Some(AppCommand::PastePattern { bank, pattern })
                } else {
                    None
                }
            })),
        },
        CommandEntry {
            name: "Reset Pattern",
            description: "Reset current pattern",
            category: "Pattern",
            keybinding: "Del",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                Some(AppCommand::OpenModal(Modal::Confirm {
                    action: crate::state::ConfirmAction::ResetPattern { bank, pattern },
                    selected: false,
                }))
            })),
        },
        CommandEntry {
            name: "Share Pattern",
            description: "Export pattern to clipboard",
            category: "Pattern",
            keybinding: "g",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                Some(AppCommand::SharePattern { bank, pattern })
            })),
        },
        CommandEntry {
            name: "Import Pattern",
            description: "Import pattern from clipboard",
            category: "Pattern",
            keybinding: "G",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                Some(AppCommand::ImportPattern { bank, pattern })
            })),
        },
        CommandEntry {
            name: "Pattern Properties",
            description: "Edit pattern properties",
            category: "Pattern",
            keybinding: "e",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                Some(AppCommand::OpenPatternPropsModal { bank, pattern })
            })),
        },
        CommandEntry {
            name: "Describe Pattern",
            description: "Add description to pattern",
            category: "Pattern",
            keybinding: "d",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let (bank, pattern) = (app.editor_ctx.bank, app.editor_ctx.pattern);
                let current = app.project_state.project.banks[bank].patterns[pattern]
                    .description
                    .clone()
                    .unwrap_or_default();
                Some(AppCommand::OpenModal(Modal::Rename {
                    target: crate::state::RenameTarget::DescribePattern { bank, pattern },
                    name: current,
                }))
            })),
        },

        // === Bank ===
        CommandEntry {
            name: "Copy Bank",
            description: "Copy current bank",
            category: "Bank",
            keybinding: "",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let bank = app.editor_ctx.bank;
                Some(AppCommand::CopyBank { bank })
            })),
        },
        CommandEntry {
            name: "Paste Bank",
            description: "Paste bank from clipboard",
            category: "Bank",
            keybinding: "",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                if app.copied_banks.is_some() {
                    let bank = app.editor_ctx.bank;
                    Some(AppCommand::PasteBank { bank })
                } else {
                    None
                }
            })),
        },
        CommandEntry {
            name: "Reset Bank",
            description: "Reset current bank",
            category: "Bank",
            keybinding: "",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let bank = app.editor_ctx.bank;
                Some(AppCommand::OpenModal(Modal::Confirm {
                    action: crate::state::ConfirmAction::ResetBank { bank },
                    selected: false,
                }))
            })),
        },
        CommandEntry {
            name: "Share Bank",
            description: "Export bank to clipboard",
            category: "Bank",
            keybinding: "",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let bank = app.editor_ctx.bank;
                Some(AppCommand::ShareBank { bank })
            })),
        },
        CommandEntry {
            name: "Import Bank",
            description: "Import bank from clipboard",
            category: "Bank",
            keybinding: "",
            pages: &[Patterns],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                let bank = app.editor_ctx.bank;
                Some(AppCommand::OpenModal(Modal::Confirm {
                    action: crate::state::ConfirmAction::ImportBank { bank },
                    selected: false,
                }))
            })),
        },

        // === Clipboard ===
        CommandEntry {
            name: "Copy Steps",
            description: "Copy selected steps",
            category: "Clipboard",
            keybinding: "Ctrl+C",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::CopySteps))),
        },
        CommandEntry {
            name: "Paste Steps",
            description: "Paste steps",
            category: "Clipboard",
            keybinding: "Ctrl+V",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                if app.editor_ctx.copied_steps.is_some() {
                    Some(AppCommand::PasteSteps)
                } else {
                    None
                }
            })),
        },
        CommandEntry {
            name: "Link Paste",
            description: "Paste as linked steps",
            category: "Clipboard",
            keybinding: "Ctrl+B",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|app| {
                if app.editor_ctx.copied_steps.is_some() {
                    Some(AppCommand::LinkPasteSteps)
                } else {
                    None
                }
            })),
        },
        CommandEntry {
            name: "Duplicate",
            description: "Duplicate selection",
            category: "Clipboard",
            keybinding: "Ctrl+D",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::DuplicateSteps))),
        },
        CommandEntry {
            name: "Harden",
            description: "Convert links to copies",
            category: "Clipboard",
            keybinding: "Ctrl+H",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::HardenSteps))),
        },

        // === Mute/Solo ===
        CommandEntry {
            name: "Mute",
            description: "Arm mute for current pattern",
            category: "Mute/Solo",
            keybinding: "m",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::MuteToggle),
        },
        CommandEntry {
            name: "Solo",
            description: "Arm solo for current pattern",
            category: "Mute/Solo",
            keybinding: "x",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::SoloToggle),
        },
        CommandEntry {
            name: "Clear Mutes",
            description: "Clear all mutes",
            category: "Mute/Solo",
            keybinding: "M",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::ClearMutes),
        },
        CommandEntry {
            name: "Clear Solos",
            description: "Clear all solos",
            category: "Mute/Solo",
            keybinding: "X",
            pages: &[Main, Patterns],
            normal_mode: false,
            action: Some(PaletteAction::ClearSolos),
        },

        // === Audio ===
        CommandEntry {
            name: "Restart Audio",
            description: "Restart audio engine",
            category: "Audio",
            keybinding: "R",
            pages: &[Engine],
            normal_mode: true,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::AudioTriggerRestart))),
        },
        CommandEntry {
            name: "Hush",
            description: "Stop all sounds gracefully",
            category: "Audio",
            keybinding: "h",
            pages: &[Engine],
            normal_mode: true,
            action: Some(PaletteAction::Hush),
        },
        CommandEntry {
            name: "Panic",
            description: "Stop all sounds immediately",
            category: "Audio",
            keybinding: "p",
            pages: &[Engine],
            normal_mode: true,
            action: Some(PaletteAction::Panic),
        },
        CommandEntry {
            name: "Test Tone",
            description: "Play test tone",
            category: "Audio",
            keybinding: "t",
            pages: &[Engine],
            normal_mode: true,
            action: Some(PaletteAction::TestTone),
        },
        CommandEntry {
            name: "Refresh Devices",
            description: "Refresh audio device list",
            category: "Audio",
            keybinding: "D",
            pages: &[Engine],
            normal_mode: true,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::AudioRefreshDevices))),
        },
        CommandEntry {
            name: "Reset Peak Voices",
            description: "Reset peak voice counter",
            category: "Audio",
            keybinding: "r",
            pages: &[Engine],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ResetPeakVoices))),
        },

        // === Display ===
        CommandEntry {
            name: "Toggle Scope",
            description: "Show/hide oscilloscope",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleScope))),
        },
        CommandEntry {
            name: "Toggle Spectrum",
            description: "Show/hide spectrum analyzer",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleSpectrum))),
        },
        CommandEntry {
            name: "Toggle Lissajous",
            description: "Show/hide Lissajous display",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleLissajous))),
        },
        CommandEntry {
            name: "Toggle Preview",
            description: "Show/hide step preview",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::TogglePreview))),
        },
        CommandEntry {
            name: "Toggle Runtime Highlight",
            description: "Toggle runtime highlighting in editor",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleRuntimeHighlight))),
        },
        CommandEntry {
            name: "Toggle Completion",
            description: "Toggle editor auto-completion",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleCompletion))),
        },
        CommandEntry {
            name: "Toggle Performance Mode",
            description: "Toggle performance mode (minimal UI)",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::TogglePerformanceMode))),
        },
        CommandEntry {
            name: "Toggle Normalize Viz",
            description: "Toggle visualization normalization",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::ToggleNormalizeViz))),
        },
        CommandEntry {
            name: "Cycle Scope Mode",
            description: "Cycle oscilloscope display mode",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::CycleScopeMode))),
        },
        CommandEntry {
            name: "Flip Scope Orientation",
            description: "Flip oscilloscope orientation",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::FlipScopeOrientation))),
        },
        CommandEntry {
            name: "Cycle Spectrum Mode",
            description: "Cycle spectrum analyzer mode",
            category: "Display",
            keybinding: "",
            pages: &[Options],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::CycleSpectrumMode))),
        },

        // === Prelude ===
        CommandEntry {
            name: "Edit Bank Prelude",
            description: "Open current bank's prelude editor",
            category: "Prelude",
            keybinding: "p",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::OpenBankPreludeEditor))),
        },
        CommandEntry {
            name: "Edit Project Prelude",
            description: "Open project-wide prelude editor",
            category: "Prelude",
            keybinding: "P",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::OpenPreludeEditor))),
        },
        CommandEntry {
            name: "Evaluate All Preludes",
            description: "Re-evaluate project and all bank preludes",
            category: "Prelude",
            keybinding: "d",
            pages: &[Main],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::EvaluatePrelude))),
        },

        // === Script ===
        CommandEntry {
            name: "Set Script Length",
            description: "Set script length via text input",
            category: "Script",
            keybinding: "L",
            pages: &[Script],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| {
                Some(AppCommand::OpenScriptModal(crate::state::ScriptField::Length))
            })),
        },
        CommandEntry {
            name: "Set Script Speed",
            description: "Set script speed via text input",
            category: "Script",
            keybinding: "S",
            pages: &[Script],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| {
                Some(AppCommand::OpenScriptModal(crate::state::ScriptField::Speed))
            })),
        },

        // === Help ===
        CommandEntry {
            name: "Search Help",
            description: "Activate help search",
            category: "Help",
            keybinding: "/",
            pages: &[Help],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::HelpActivateSearch))),
        },
        CommandEntry {
            name: "Search Dictionary",
            description: "Activate dictionary search",
            category: "Help",
            keybinding: "/",
            pages: &[Dict],
            normal_mode: false,
            action: Some(PaletteAction::Resolve(|_| Some(AppCommand::DictActivateSearch))),
        },

        // ==========================================================
        // Keybinding-only entries (action: None) — shown in help modal only
        // ==========================================================

        // Global
        CommandEntry {
            name: "Navigate views",
            description: "Switch between adjacent views",
            category: "Navigation",
            keybinding: "Ctrl+\u{2190}\u{2192}\u{2191}\u{2193}",
            pages: &[],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Go to view",
            description: "Dict/Patterns/Options/Help/Sequencer/Engine/Script",
            category: "Navigation",
            keybinding: "F1\u{2013}F7",
            pages: &[],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Full restart",
            description: "Full restart from step 0",
            category: "Playback",
            keybinding: "F12",
            pages: &[],
            normal_mode: true,
            action: None,
        },
        CommandEntry {
            name: "Keybindings",
            description: "Show keybindings help",
            category: "Help",
            keybinding: "?",
            pages: &[],
            normal_mode: false,
            action: None,
        },

        // Main page keybinding-only
        CommandEntry {
            name: "Navigate",
            description: "Move cursor between steps",
            category: "Editing",
            keybinding: "\u{2190}\u{2192}\u{2191}\u{2193}",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Select",
            description: "Extend selection",
            category: "Editing",
            keybinding: "Shift+\u{2190}\u{2192}\u{2191}\u{2193}",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Clear Selection",
            description: "Clear selection",
            category: "Editing",
            keybinding: "Esc",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Samples",
            description: "Toggle sample browser",
            category: "Editing",
            keybinding: "Tab",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Delete",
            description: "Delete step(s)",
            category: "Editing",
            keybinding: "Del",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Run Step",
            description: "Run step script immediately",
            category: "Editing",
            keybinding: "Ctrl+R",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Fill",
            description: "Toggle fill mode (hold)",
            category: "Editing",
            keybinding: "f",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Command Palette",
            description: "Open command palette",
            category: "Editing",
            keybinding: ":",
            pages: &[],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Prev/Next Pattern",
            description: "Previous/next pattern",
            category: "Navigation",
            keybinding: "Alt+\u{2191}\u{2193}",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Prev/Next Bank",
            description: "Previous/next bank",
            category: "Navigation",
            keybinding: "Alt+\u{2190}\u{2192}",
            pages: &[Main],
            normal_mode: false,
            action: None,
        },

        // Patterns page keybinding-only
        CommandEntry {
            name: "Navigate",
            description: "Move between banks/patterns",
            category: "Navigation",
            keybinding: "\u{2190}\u{2192}\u{2191}\u{2193}",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Select",
            description: "Extend selection",
            category: "Navigation",
            keybinding: "Shift+\u{2191}\u{2193}",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Shift Patterns",
            description: "Move patterns up/down",
            category: "Pattern",
            keybinding: "Alt+\u{2191}\u{2193}",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Select Pattern",
            description: "Select pattern for editing",
            category: "Pattern",
            keybinding: "Enter",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Back",
            description: "Clear armed or go back",
            category: "Pattern",
            keybinding: "Esc",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Launch",
            description: "Launch armed changes",
            category: "Pattern",
            keybinding: "c",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Arm Play",
            description: "Arm pattern play toggle",
            category: "Pattern",
            keybinding: "p",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Rename",
            description: "Rename bank/pattern",
            category: "Pattern",
            keybinding: "r",
            pages: &[Patterns],
            normal_mode: false,
            action: None,
        },

        // Engine page keybinding-only
        CommandEntry {
            name: "Section",
            description: "Next/previous section",
            category: "Navigation",
            keybinding: "Tab/BackTab",
            pages: &[Engine],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Switch/Adjust",
            description: "Switch device type or adjust setting",
            category: "Audio",
            keybinding: "\u{2190}\u{2192}",
            pages: &[Engine],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Navigate",
            description: "Navigate list items",
            category: "Audio",
            keybinding: "\u{2191}\u{2193}",
            pages: &[Engine],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Page",
            description: "Page through device list",
            category: "Audio",
            keybinding: "PgUp/Dn",
            pages: &[Engine],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Select",
            description: "Select device",
            category: "Audio",
            keybinding: "Enter",
            pages: &[Engine],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Add Path",
            description: "Add sample path",
            category: "Audio",
            keybinding: "A",
            pages: &[Engine],
            normal_mode: false,
            action: None,
        },

        // Options page keybinding-only
        CommandEntry {
            name: "Next",
            description: "Move to next option",
            category: "Display",
            keybinding: "Tab",
            pages: &[Options],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Previous",
            description: "Move to previous option",
            category: "Display",
            keybinding: "Shift+Tab",
            pages: &[Options],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Navigate",
            description: "Navigate options",
            category: "Display",
            keybinding: "\u{2191}\u{2193}",
            pages: &[Options],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Toggle",
            description: "Toggle or adjust option",
            category: "Display",
            keybinding: "\u{2190}\u{2192}",
            pages: &[Options],
            normal_mode: false,
            action: None,
        },

        // Help page keybinding-only
        CommandEntry {
            name: "Scroll",
            description: "Scroll content",
            category: "Help",
            keybinding: "\u{2191}\u{2193} j/k",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Topic",
            description: "Next/previous topic",
            category: "Help",
            keybinding: "Tab/BackTab",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Page",
            description: "Page scroll",
            category: "Help",
            keybinding: "PgUp/Dn",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Next Code Block",
            description: "Jump to next code block",
            category: "Help",
            keybinding: "n",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Prev Code Block",
            description: "Jump to previous code block",
            category: "Help",
            keybinding: "p",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Run Code",
            description: "Execute focused code block",
            category: "Help",
            keybinding: "Enter",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Clear",
            description: "Clear search / deselect block",
            category: "Help",
            keybinding: "Esc",
            pages: &[Help],
            normal_mode: false,
            action: None,
        },

        // Dict page keybinding-only
        CommandEntry {
            name: "Focus",
            description: "Toggle category/words focus",
            category: "Help",
            keybinding: "Tab",
            pages: &[Dict],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Navigate",
            description: "Navigate items",
            category: "Help",
            keybinding: "\u{2191}\u{2193} j/k",
            pages: &[Dict],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Page",
            description: "Page scroll",
            category: "Help",
            keybinding: "PgUp/Dn",
            pages: &[Dict],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Clear",
            description: "Clear search",
            category: "Help",
            keybinding: "Esc",
            pages: &[Dict],
            normal_mode: false,
            action: None,
        },

        // Script page keybinding-only
        CommandEntry {
            name: "Focus",
            description: "Focus editor for typing",
            category: "Script",
            keybinding: "Enter",
            pages: &[Script],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Unfocus",
            description: "Unfocus editor to use page keybindings",
            category: "Script",
            keybinding: "Esc",
            pages: &[Script],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Evaluate",
            description: "Compile and check for errors",
            category: "Script",
            keybinding: "Ctrl+E",
            pages: &[Script],
            normal_mode: false,
            action: None,
        },
        CommandEntry {
            name: "Stack Preview",
            description: "Toggle stack preview",
            category: "Script",
            keybinding: "Ctrl+S",
            pages: &[Script],
            normal_mode: false,
            action: None,
        },
    ]
});

pub fn bindings_for(page: Page, plugin_mode: bool) -> Vec<(&'static str, &'static str, &'static str)> {
    COMMANDS
        .iter()
        .filter(|e| e.pages.is_empty() || e.pages.contains(&page))
        .filter(|e| !plugin_mode || !e.normal_mode)
        .map(|e| (e.keybinding, e.name, e.description))
        .collect()
}

pub fn palette_entries<'a>(
    query: &str,
    plugin_mode: bool,
    app: &App,
) -> Vec<&'a CommandEntry> {
    use cagire_ratatui::fuzzy_match;

    let filtered: Vec<(usize, &CommandEntry)> = COMMANDS
        .iter()
        .filter(|e| e.action.is_some())
        .filter(|e| !plugin_mode || !e.normal_mode)
        .filter(|e| match &e.action {
            Some(PaletteAction::Resolve(f)) => f(app).is_some(),
            _ => true,
        })
        .filter_map(|e| {
            if query.is_empty() {
                return Some((0, e));
            }
            [
                fuzzy_match(query, e.name),
                fuzzy_match(query, e.description),
                fuzzy_match(query, e.category),
                fuzzy_match(query, e.keybinding),
            ]
            .into_iter()
            .flatten()
            .min()
            .map(|score| (score, e))
        })
        .collect();

    let mut sorted = filtered;
    sorted.sort_by_key(|(score, e)| (*score, category_index(e.category)));
    sorted.into_iter().map(|(_, e)| e).collect()
}
