//! Key binding system for mapping key sequences to commands

use crate::command::builtin::ToggleExplorerCommand;
use crate::command::{id::builtin, registry::CommandRegistry, CommandId, CommandTrait};
use crate::event::WhichKeyBinding;
use crate::modd::{EditMode, Focus, ModeState, SubMode};
use std::collections::HashMap;
use std::sync::Arc;

/// Reference to a command - either by ID (for registered commands) or inline
#[derive(Debug, Clone)]
pub enum CommandRef {
    /// Reference to a registered command by ID
    Registered(CommandId),
    /// Inline command with parameters (for parameterized commands like `InsertChar`)
    Inline(Arc<dyn CommandTrait>),
}

/// Node in the keymap trie
pub struct KeyMapInner {
    /// If this is a terminal node, the command to execute
    pub command: Option<CommandRef>,
    /// Children for multi-key sequences (e.g., "dd", "gg")
    #[allow(dead_code)] // Infrastructure for proper trie-based lookup
    pub next: HashMap<String, Self>,
}

impl KeyMapInner {
    #[must_use]
    pub fn new() -> Self {
        Self {
            command: None,
            next: HashMap::new(),
        }
    }

    /// Create a node with a `CommandRef`
    #[must_use]
    pub fn with_command_ref(cmd: CommandRef) -> Self {
        Self {
            command: Some(cmd),
            next: HashMap::new(),
        }
    }

    /// Create a node with a registered command ID
    #[must_use]
    pub fn with_command_id(id: CommandId) -> Self {
        Self {
            command: Some(CommandRef::Registered(id)),
            next: HashMap::new(),
        }
    }

    /// Create a node with an inline command
    #[must_use]
    pub fn with_inline_command(cmd: Arc<dyn CommandTrait>) -> Self {
        Self {
            command: Some(CommandRef::Inline(cmd)),
            next: HashMap::new(),
        }
    }

    /// Get the description for this binding
    ///
    /// Returns the command's description if available, or a prefix indicator.
    #[must_use]
    pub fn get_description(&self, registry: &CommandRegistry) -> String {
        match &self.command {
            Some(CommandRef::Registered(id)) => registry
                .get(id)
                .map_or_else(|| id.as_str().to_string(), |cmd| cmd.description().to_string()),
            Some(CommandRef::Inline(cmd)) => cmd.description().to_string(),
            None => "+prefix".to_string(),
        }
    }

    /// Check if this is a prefix node (has no command, only children)
    #[must_use]
    pub const fn is_prefix(&self) -> bool {
        self.command.is_none()
    }
}

impl Default for KeyMapInner {
    fn default() -> Self {
        Self::new()
    }
}

impl std::fmt::Debug for KeyMapInner {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("KeyMapInner")
            .field("command", &self.command)
            .field("next_keys", &self.next.keys().collect::<Vec<_>>())
            .finish()
    }
}

/// Keymap for each mode
///
/// Keymaps are organized by Focus + `EditMode` + `SubMode`:
/// - Editor + Normal → normal
/// - Editor + Insert → insert
/// - Editor + Visual → visual
/// - Explorer + Normal → explorer
/// - Explorer + Insert → `explorer_input`
/// - Telescope + Normal → `telescope_normal`
/// - Telescope + Insert → `telescope_insert`
/// - Any + Command → command
/// - Any + `OperatorPending` → `operator_pending`
#[derive(Default)]
pub struct KeyMap {
    pub insert: HashMap<String, KeyMapInner>,
    pub normal: HashMap<String, KeyMapInner>,
    pub command: HashMap<String, KeyMapInner>,
    pub visual: HashMap<String, KeyMapInner>,
    pub explorer: HashMap<String, KeyMapInner>,
    pub explorer_input: HashMap<String, KeyMapInner>,
    pub operator_pending: HashMap<String, KeyMapInner>,
    pub telescope_normal: HashMap<String, KeyMapInner>,
    pub telescope_insert: HashMap<String, KeyMapInner>,
    pub leap: HashMap<String, KeyMapInner>,
}

impl KeyMap {
    #[must_use]
    pub fn with_defaults() -> Self {
        let mut km = Self::default();
        Self::setup_normal_mode(&mut km.normal);
        Self::setup_insert_mode(&mut km.insert);
        Self::setup_visual_mode(&mut km.visual);
        Self::setup_command_mode(&mut km.command);
        Self::setup_explorer_mode(&mut km.explorer);
        Self::setup_explorer_input_mode(&mut km.explorer_input);
        Self::setup_operator_pending_mode(&mut km.operator_pending);
        Self::setup_telescope_normal_mode(&mut km.telescope_normal);
        Self::setup_telescope_insert_mode(&mut km.telescope_insert);
        Self::setup_leap_mode(&mut km.leap);
        km
    }

    /// Bind a key sequence to a command reference at runtime
    ///
    /// # Arguments
    /// * `mode` - Mode identifier: n/normal, i/insert, v/visual, c/command,
    ///   tn/telescope\_normal, ti/telescope\_insert
    /// * `keys` - Key sequence (e.g., "jj", "<leader>x")
    /// * `cmd` - Command reference to bind
    pub fn bind(&mut self, mode: &str, keys: &str, cmd: CommandRef) {
        let map = match mode {
            "n" | "normal" => &mut self.normal,
            "i" | "insert" => &mut self.insert,
            "v" | "visual" => &mut self.visual,
            "c" | "command" => &mut self.command,
            "e" | "explorer" => &mut self.explorer,
            "E" | "explorer_input" => &mut self.explorer_input,
            "o" | "operator_pending" => &mut self.operator_pending,
            "tn" | "telescope_normal" => &mut self.telescope_normal,
            "ti" | "telescope_insert" => &mut self.telescope_insert,
            "l" | "leap" => &mut self.leap,
            _ => return,
        };
        map.insert(keys.to_string(), KeyMapInner::with_command_ref(cmd));
    }

    /// Bind a key sequence to a registered command ID at runtime
    pub fn bind_id(&mut self, mode: &str, keys: &str, id: CommandId) {
        self.bind(mode, keys, CommandRef::Registered(id));
    }

    /// Unbind a key sequence
    pub fn unbind(&mut self, mode: &str, keys: &str) {
        let map = match mode {
            "n" | "normal" => &mut self.normal,
            "i" | "insert" => &mut self.insert,
            "v" | "visual" => &mut self.visual,
            "c" | "command" => &mut self.command,
            "e" | "explorer" => &mut self.explorer,
            "E" | "explorer_input" => &mut self.explorer_input,
            "o" | "operator_pending" => &mut self.operator_pending,
            "tn" | "telescope_normal" => &mut self.telescope_normal,
            "ti" | "telescope_insert" => &mut self.telescope_insert,
            "l" | "leap" => &mut self.leap,
            _ => return,
        };
        map.remove(keys);
    }

    /// Get the appropriate keymap for a given `ModeState`
    ///
    /// Keymap selection priority:
    /// 1. `SubMode` takes precedence (Command, `OperatorPending`)
    /// 2. Focus + `EditMode` determines the keymap otherwise
    #[must_use]
    pub const fn get_keymap_for_mode(&self, mode: &ModeState) -> &HashMap<String, KeyMapInner> {
        // SubMode takes precedence
        match &mode.sub_mode {
            SubMode::Command => return &self.command,
            SubMode::OperatorPending { .. } => return &self.operator_pending,
            SubMode::Leap { .. } => return &self.leap,
            SubMode::None => {}
        }

        // Focus + EditMode determines keymap
        match (&mode.focus, &mode.edit_mode) {
            (Focus::Editor, EditMode::Normal) => &self.normal,
            (Focus::Editor, EditMode::Insert(_)) => &self.insert,
            (Focus::Editor, EditMode::Visual(_)) => &self.visual,
            (Focus::Explorer, EditMode::Normal | EditMode::Visual(_)) => &self.explorer,
            (Focus::Explorer, EditMode::Insert(_)) => &self.explorer_input,
            (Focus::Telescope, EditMode::Normal | EditMode::Visual(_)) => &self.telescope_normal,
            (Focus::Telescope, EditMode::Insert(_)) => &self.telescope_insert,
        }
    }

    /// Get all available bindings for a given prefix in a mode
    ///
    /// This is used by the which-key feature to display available keybindings.
    /// Keymap selection is based on Focus + `EditMode` + `SubMode`:
    /// - `SubMode` takes precedence (Command, `OperatorPending`)
    /// - Then Focus + `EditMode` determines the keymap
    #[must_use]
    pub fn get_bindings_for_prefix(
        &self,
        mode: &ModeState,
        prefix: &str,
        registry: &CommandRegistry,
    ) -> Vec<WhichKeyBinding> {
        let keymap = self.get_keymap_for_mode(mode);

        let mut bindings = Vec::new();
        let mut seen_keys = std::collections::HashSet::new();

        for (key, inner) in keymap {
            // Check if key starts with the prefix and is longer
            if key.starts_with(prefix) && key.len() > prefix.len() {
                // Get the next key segment after the prefix
                let suffix = &key[prefix.len()..];
                let next_key = Self::first_key_segment(suffix);

                // Avoid duplicates (e.g., "gg" and "gG" both show "g" after "g" prefix)
                if seen_keys.contains(next_key) {
                    continue;
                }
                seen_keys.insert(next_key.to_string());

                let description = inner.get_description(registry);
                let is_prefix = inner.is_prefix();

                bindings.push(WhichKeyBinding {
                    key: next_key.to_string(),
                    description,
                    is_prefix,
                });
            }
        }

        // Sort by key for consistent display
        bindings.sort_by(|a, b| a.key.cmp(&b.key));
        bindings
    }

    /// Extract the first key segment from a key sequence
    ///
    /// Handles special keys like `<C-x>`, `<Escape>`, etc.
    fn first_key_segment(s: &str) -> &str {
        // Handle special keys like <C-x>, <Escape>, etc.
        if s.starts_with('<')
            && let Some(end) = s.find('>')
        {
            return &s[..=end];
        }
        // Single character key
        s.chars().next().map_or(s, |c| &s[..c.len_utf8()])
    }

    fn setup_normal_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // Movement
        keymap.insert("h".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_LEFT));
        keymap.insert("j".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_DOWN));
        keymap.insert("k".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_UP));
        keymap.insert("l".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_RIGHT));
        keymap.insert("0".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_LINE_START));
        keymap.insert("$".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_LINE_END));
        keymap.insert("w".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_WORD_FORWARD));
        keymap.insert("b".to_string(), KeyMapInner::with_command_id(builtin::CURSOR_WORD_BACKWARD));

        // Mode switching
        keymap.insert("i".to_string(), KeyMapInner::with_command_id(builtin::ENTER_INSERT_MODE));
        keymap.insert("a".to_string(), KeyMapInner::with_command_id(builtin::ENTER_INSERT_MODE_AFTER));
        keymap.insert("A".to_string(), KeyMapInner::with_command_id(builtin::ENTER_INSERT_MODE_EOL));
        keymap.insert("o".to_string(), KeyMapInner::with_command_id(builtin::OPEN_LINE_BELOW));
        keymap.insert("O".to_string(), KeyMapInner::with_command_id(builtin::OPEN_LINE_ABOVE));
        keymap.insert("v".to_string(), KeyMapInner::with_command_id(builtin::ENTER_VISUAL_MODE));
        keymap.insert("<C-v>".to_string(), KeyMapInner::with_command_id(builtin::ENTER_VISUAL_BLOCK_MODE));
        keymap.insert(":".to_string(), KeyMapInner::with_command_id(builtin::ENTER_COMMAND_MODE));

        // Editing
        keymap.insert("x".to_string(), KeyMapInner::with_command_id(builtin::DELETE_CHAR_FORWARD));
        keymap.insert("p".to_string(), KeyMapInner::with_command_id(builtin::PASTE));
        keymap.insert("P".to_string(), KeyMapInner::with_command_id(builtin::PASTE_BEFORE));

        // g-prefix bindings
        keymap.insert("g".to_string(), KeyMapInner::new()); // prefix, no command
        keymap.insert("gg".to_string(), KeyMapInner::with_command_id(builtin::GOTO_FIRST_LINE));
        keymap.insert("G".to_string(), KeyMapInner::with_command_id(builtin::GOTO_LAST_LINE));

        // Jump list navigation
        keymap.insert("<C-o>".to_string(), KeyMapInner::with_command_id(builtin::JUMP_OLDER));
        keymap.insert("<C-i>".to_string(), KeyMapInner::with_command_id(builtin::JUMP_NEWER));

        // Undo/Redo
        keymap.insert("u".to_string(), KeyMapInner::with_command_id(builtin::UNDO));
        keymap.insert("<C-r>".to_string(), KeyMapInner::with_command_id(builtin::REDO));

        // Operators (d, y, c enter operator-pending mode)
        keymap.insert("d".to_string(), KeyMapInner::with_command_id(builtin::ENTER_DELETE_OPERATOR));
        keymap.insert("dd".to_string(), KeyMapInner::with_command_id(builtin::DELETE_LINE));
        keymap.insert("y".to_string(), KeyMapInner::with_command_id(builtin::ENTER_YANK_OPERATOR));
        keymap.insert("yy".to_string(), KeyMapInner::with_command_id(builtin::YANK_LINE));
        keymap.insert("Y".to_string(), KeyMapInner::with_command_id(builtin::YANK_TO_END));
        keymap.insert("c".to_string(), KeyMapInner::with_command_id(builtin::ENTER_CHANGE_OPERATOR));

        // Space (leader) bindings
        keymap.insert(" ".to_string(), KeyMapInner::new()); // prefix, no command
        keymap.insert(
            " e".to_string(),
            KeyMapInner::with_inline_command(Arc::new(ToggleExplorerCommand)),
        );

        // Telescope bindings (Space + f prefix)
        keymap.insert(" f".to_string(), KeyMapInner::new()); // prefix, no command
        keymap.insert(" ff".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_FIND_FILES));
        keymap.insert(" fb".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_FIND_BUFFERS));
        keymap.insert(" fg".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_LIVE_GREP));
        keymap.insert(" fr".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_RECENT));
        keymap.insert(" fc".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_COMMANDS));
        keymap.insert(" fh".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_HELP));
        keymap.insert(" fk".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_KEYMAPS));

        // Leap motion bindings
        keymap.insert("s".to_string(), KeyMapInner::with_command_id(builtin::LEAP_FORWARD));
        keymap.insert("S".to_string(), KeyMapInner::with_command_id(builtin::LEAP_BACKWARD));

        // z-prefix bindings (code folding)
        keymap.insert("z".to_string(), KeyMapInner::new()); // prefix, no command
        keymap.insert("za".to_string(), KeyMapInner::with_command_id(builtin::FOLD_TOGGLE));
        keymap.insert("zo".to_string(), KeyMapInner::with_command_id(builtin::FOLD_OPEN));
        keymap.insert("zc".to_string(), KeyMapInner::with_command_id(builtin::FOLD_CLOSE));
        keymap.insert("zR".to_string(), KeyMapInner::with_command_id(builtin::FOLD_OPEN_ALL));
        keymap.insert("zM".to_string(), KeyMapInner::with_command_id(builtin::FOLD_CLOSE_ALL));
    }

    fn setup_insert_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::ENTER_NORMAL_MODE));
        keymap.insert("Backspace".to_string(), KeyMapInner::with_command_id(builtin::DELETE_CHAR_BACKWARD));
        keymap.insert("Enter".to_string(), KeyMapInner::with_command_id(builtin::INSERT_NEWLINE));

        // Completion keybindings
        keymap.insert("C-Space".to_string(), KeyMapInner::with_command_id(builtin::COMPLETION_TRIGGER));
        keymap.insert("C-n".to_string(), KeyMapInner::with_command_id(builtin::COMPLETION_NEXT));
        keymap.insert("C-p".to_string(), KeyMapInner::with_command_id(builtin::COMPLETION_PREV));
        keymap.insert("Tab".to_string(), KeyMapInner::with_command_id(builtin::COMPLETION_CONFIRM));
        keymap.insert("C-e".to_string(), KeyMapInner::with_command_id(builtin::COMPLETION_DISMISS));
    }

    fn setup_visual_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::ENTER_NORMAL_MODE));
        keymap.insert("h".to_string(), KeyMapInner::with_command_id(builtin::VISUAL_EXTEND_LEFT));
        keymap.insert("j".to_string(), KeyMapInner::with_command_id(builtin::VISUAL_EXTEND_DOWN));
        keymap.insert("k".to_string(), KeyMapInner::with_command_id(builtin::VISUAL_EXTEND_UP));
        keymap.insert("l".to_string(), KeyMapInner::with_command_id(builtin::VISUAL_EXTEND_RIGHT));
        keymap.insert("d".to_string(), KeyMapInner::with_command_id(builtin::VISUAL_DELETE));
        keymap.insert("y".to_string(), KeyMapInner::with_command_id(builtin::VISUAL_YANK));
    }

    fn setup_command_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::COMMAND_LINE_CANCEL));
        keymap.insert("Enter".to_string(), KeyMapInner::with_command_id(builtin::COMMAND_LINE_EXECUTE));
        keymap.insert("Backspace".to_string(), KeyMapInner::with_command_id(builtin::COMMAND_LINE_BACKSPACE));
    }

    fn setup_explorer_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // Navigation
        keymap.insert("j".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CURSOR_DOWN));
        keymap.insert("k".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CURSOR_UP));
        keymap.insert("Ctrl+d".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_PAGE_DOWN));
        keymap.insert("Ctrl+u".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_PAGE_UP));
        keymap.insert("g".to_string(), KeyMapInner::new()); // prefix
        keymap.insert("gg".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_GOTO_FIRST));
        keymap.insert("G".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_GOTO_LAST));

        // Tree operations
        keymap.insert("Enter".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_OPEN_NODE));
        keymap.insert("o".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_TOGGLE_NODE));
        keymap.insert("x".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CLOSE_PARENT));
        keymap.insert("u".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_GO_TO_PARENT));
        keymap.insert("R".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_REFRESH));

        // Display
        keymap.insert("I".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_TOGGLE_HIDDEN));

        // File operations
        keymap.insert("a".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CREATE_FILE));
        keymap.insert("A".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CREATE_DIR));
        keymap.insert("r".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_RENAME));
        keymap.insert("d".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_DELETE));

        // Filter
        keymap.insert("/".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_FILTER));
        keymap.insert("C".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CLEAR_FILTER));

        // Window control
        keymap.insert("q".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CLOSE));
        keymap.insert("Tab".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_FOCUS_EDITOR));
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_FOCUS_EDITOR));
    }

    fn setup_explorer_input_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // In explorer input mode, we only handle special keys
        // Characters are handled via inline commands in the command handler
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CANCEL_INPUT));
        keymap.insert("Enter".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_CONFIRM_INPUT));
        keymap.insert("Backspace".to_string(), KeyMapInner::with_command_id(builtin::EXPLORER_INPUT_BACKSPACE));
    }

    fn setup_operator_pending_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // Escape cancels operator-pending mode
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::ENTER_NORMAL_MODE));
        // Motion keys and 'd' for dd are handled dynamically in CommandHandler
    }

    /// Telescope Normal mode - navigation keys (j/k/gg/G)
    fn setup_telescope_normal_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // Navigation
        keymap.insert("j".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_NEXT));
        keymap.insert("k".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PREV));
        keymap.insert("g".to_string(), KeyMapInner::new()); // prefix
        keymap.insert("gg".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_GOTO_FIRST));
        keymap.insert("G".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_GOTO_LAST));
        keymap.insert("C-d".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PAGE_DOWN));
        keymap.insert("C-u".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PAGE_UP));

        // Mode switching
        keymap.insert("i".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_ENTER_INSERT));

        // Actions
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_CLOSE));
        keymap.insert("Enter".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_CONFIRM));
    }

    /// Telescope Insert mode - typing query with Ctrl-based navigation
    fn setup_telescope_insert_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // Navigation (Ctrl-based to not interfere with typing)
        keymap.insert("C-n".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_NEXT));
        keymap.insert("C-p".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PREV));
        keymap.insert("Down".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_NEXT));
        keymap.insert("Up".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PREV));
        keymap.insert("Tab".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_NEXT));
        keymap.insert("S-Tab".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PREV));
        keymap.insert("C-u".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PAGE_UP));
        keymap.insert("C-d".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_PAGE_DOWN));

        // Editing
        keymap.insert("Backspace".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_DELETE_CHAR));

        // Mode switching (ESC goes to Normal mode in Telescope, not closes)
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_ENTER_NORMAL));

        // Actions
        keymap.insert("Enter".to_string(), KeyMapInner::with_command_id(builtin::TELESCOPE_CONFIRM));
    }

    fn setup_leap_mode(keymap: &mut HashMap<String, KeyMapInner>) {
        // Escape cancels leap mode
        keymap.insert("Escape".to_string(), KeyMapInner::with_command_id(builtin::LEAP_CANCEL));
        // All other keys (characters for search pattern or label selection) are handled
        // directly in CommandHandler without going through keymap
    }
}
