//! Translation from raw `crossterm` key events to high-level editor actions.
//!
//! Only the *normal* editing mode is mapped here — modal prompts (search,
//! save-as, quit confirm, help overlay) interpret keys directly in the editor.

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

/// High-level user intents that the editor dispatches on.
#[derive(Debug, Clone)]
pub enum Action {
    /// Quit (prompts to save if any buffer is modified).
    Quit,
    /// Save in place (falls back to `SaveAs` if there is no path).
    Save,
    /// Prompt for a filename and save there.
    SaveAs,
    /// Open the incremental search bar.
    Find,
    /// Show / dismiss the help overlay.
    Help,
    /// Toggle the line-number gutter.
    ToggleLineNumbers,
    /// Open a new empty buffer in its own tab.
    NewTab,
    /// Cycle to the next tab.
    CycleTab,
    /// Close the current tab (quits if it is the only tab).
    CloseTab,
    /// Undo the last edit.
    Undo,
    /// Redo the last undone edit.
    Redo,
    /// Cursor: left one grapheme cluster.
    MoveLeft,
    /// Cursor: right one grapheme cluster.
    MoveRight,
    /// Cursor: up one display line.
    MoveUp,
    /// Cursor: down one display line.
    MoveDown,
    /// Cursor: start of line.
    MoveHome,
    /// Cursor: end of line.
    MoveEnd,
    /// Cursor: previous word.
    MoveWordLeft,
    /// Cursor: next word.
    MoveWordRight,
    /// Cursor: up one screen.
    PageUp,
    /// Cursor: down one screen.
    PageDown,
    /// Insert a literal character at the cursor.
    InsertChar(char),
    /// Insert a line break.
    InsertNewline,
    /// Insert an indent (`tab_size` spaces).
    InsertTab,
    /// Delete the grapheme before the cursor.
    Backspace,
    /// Delete the grapheme at the cursor.
    Delete,
    /// Cancel (Esc).
    Cancel,
    /// No-op.
    Nothing,
}

/// Translate a key event in normal mode to an [`Action`].
pub fn key_to_action(ev: KeyEvent) -> Action {
    use KeyCode::*;
    let ctrl = ev.modifiers.contains(KeyModifiers::CONTROL);
    let shift = ev.modifiers.contains(KeyModifiers::SHIFT);

    if ctrl {
        match ev.code {
            Char('q') | Char('Q') => return Action::Quit,
            Char('s') | Char('S') if shift => return Action::SaveAs,
            Char('s') | Char('S') => return Action::Save,
            Char('f') | Char('F') => return Action::Find,
            Char('n') | Char('N') => return Action::ToggleLineNumbers,
            Char('t') | Char('T') => return Action::NewTab,
            Char('w') | Char('W') => return Action::CloseTab,
            Tab => return Action::CycleTab,
            Char('z') | Char('Z') => return Action::Undo,
            Char('y') | Char('Y') => return Action::Redo,
            Char('h') | Char('H') => return Action::Help,
            Left => return Action::MoveWordLeft,
            Right => return Action::MoveWordRight,
            _ => {}
        }
    }
    match ev.code {
        F(1) => Action::Help,
        Left => Action::MoveLeft,
        Right => Action::MoveRight,
        Up => Action::MoveUp,
        Down => Action::MoveDown,
        Home => Action::MoveHome,
        End => Action::MoveEnd,
        PageUp => Action::PageUp,
        PageDown => Action::PageDown,
        Enter => Action::InsertNewline,
        Tab => Action::InsertTab,
        Backspace => Action::Backspace,
        Delete => Action::Delete,
        Esc => Action::Cancel,
        Char(c) if !c.is_control() => Action::InsertChar(c),
        _ => Action::Nothing,
    }
}
