use super::ComponentManager;
use crate::app::{AppState, Action};
use crate::input::InputEvent;
use crate::errors::ComponentError;
use crate::config;

pub fn handle_event(
    manager: &mut ComponentManager,
    event: InputEvent,
    state: &AppState,
) -> Result<Option<Action>, ComponentError> {
    // Edit modal has top priority when active (edit is stronger than reword).
    if state.edit_modal_open {
        return handle_edit_input(event, state);
    }

    // Reword modal has priority when active.
    if state.reword_modal_open {
        return handle_reword_input(event, state);
    }

    // Commit mode has priority when active.
    if state.commit_mode {
        return handle_commit_mode_with_amend(event, state);
    }

    // Branch create mode has priority when active.
    if state.branch_create_mode {
        return handle_branch_create_mode(event, state);
    }

    // Stash create mode has priority when active.
    if state.stash_create_mode {
        return handle_stash_create_mode(event, state);
    }

    // Rebase builder has priority (new UI)
    if state.rebase_editor_open {
        return handle_rebase_builder(event, state);
    }

    // Confirm modal has priority.
    if state.confirm_action.is_some() {
        if let InputEvent::Key(key) = &event {
            if key.kind == crossterm::event::KeyEventKind::Press {
                use crossterm::event::KeyCode::*;
                return Ok(match key.code {
                    Enter => Some(Action::ConfirmExecute),
                    Esc => Some(Action::ConfirmCancel),
                    _ => None,
                });
            }
        }
        return Ok(None);
    }

    // Log action menu has priority when open.
    if state.log_action_menu {
        tracing::debug!("handle_event: Routing to log_action_menu handler, selected={}", state.log_action_selected);
        return handle_log_action_menu(event, state);
    }

    // Op log popup.
    if state.show_op_log {
        return handle_op_log(event);
    }

    // Merge notifier log popup.
    if state.show_merge_log {
        return handle_merge_log(event);
    }

    // Rebase todo popup.
    if state.show_rebase_todo {
        return handle_rebase_todo(event, state);
    }

    // Conflicts popup has priority when open.
    if state.conflicts_popup {
        return handle_conflicts_popup(event, state);
    }

    // Conflicts guided helper.
    if state.conflicts_guided {
        return handle_conflicts_guided(event, state);
    }

    // PR helper popup.
    if state.pr_helper {
        return handle_pr_helper(event, state);
    }

    // Theme picker has priority when open.
    if state.theme_picker {
        return handle_theme_picker(event, state);
    }

    // Diff focus: capture navigation keys for the diff pane.
    if state.diff_focus {
        return handle_diff_focus(event);
    }

    // Check for pending reset cancellation (Esc key)
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            if let crossterm::event::KeyCode::Esc = key.code {
                if state.reset_pending.is_some() {
                    return Ok(Some(Action::CancelReset));
                }
            }
        }
    }

    // Check global keys BEFORE command palette to ensure shortcuts work when palette is closed
    // This must happen before command palette check so global shortcuts work when palette is closed
    if !state.command_palette {
        // Try unified shortcut handler first (supports multi-character shortcuts)
        if let Some(action) = manager.shortcut_handler.handle_keypress(event.clone(), state)? {
            return Ok(Some(action));
        }
        // Fallback to legacy global keys for navigation and special keys
        if let Some(action) = handle_global_keys(event.clone(), state)? {
            return Ok(Some(action));
        }
    }

    // Command palette is now handled by ComponentManager::handle_event using new palette system
    // Old handle_command_palette is no longer used for commands (only kept for backward compatibility)

    // Merge base picker
    if state.merge_base_picker {
        return handle_merge_base_picker(event, state);
    }

    // If help overlay is open, capture navigation keys before delegating.
    if state.show_help {
        return handle_help(event, state);
    }

    // Try active component last
    if let Some(action) = handle_active_component(event, state, manager)? {
        return Ok(Some(action));
    }
    
    Ok(None)
}

fn handle_commit_mode_with_amend(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            use crate::app::state::AmendField;
            
            // Handle Tab navigation in amend mode
            if state.amend_mode && key.code == Tab {
                let next_field = match state.amend_editing_field {
                    None | Some(AmendField::Message) => Some(AmendField::AuthorName),
                    Some(AmendField::AuthorName) => Some(AmendField::AuthorEmail),
                    Some(AmendField::AuthorEmail) => Some(AmendField::Message),
                };
                return Ok(Some(Action::SetAmendEditingField(next_field)));
            }
            
            // Route input to appropriate field based on amend_editing_field
            let editing_field = if state.amend_mode {
                state.amend_editing_field.unwrap_or(AmendField::Message)
            } else {
                AmendField::Message // Normal commit mode always edits message
            };
            
            return Ok(match key.code {
                Esc => Some(Action::CancelCommit),
                Enter => Some(Action::CommitSubmit),
                Backspace => {
                    match editing_field {
                        AmendField::Message => Some(Action::CommitInputBackspace),
                        AmendField::AuthorName => {
                            let mut name = state.amend_author_name.clone();
                            name.pop();
                            Some(Action::SetAmendAuthorName(name))
                        }
                        AmendField::AuthorEmail => {
                            let mut email = state.amend_author_email.clone();
                            email.pop();
                            Some(Action::SetAmendAuthorEmail(email))
                        }
                    }
                }
                Char(c) => {
                    match editing_field {
                        AmendField::Message => Some(Action::CommitInputChar(c)),
                        AmendField::AuthorName => {
                            let mut name = state.amend_author_name.clone();
                            name.push(c);
                            Some(Action::SetAmendAuthorName(name))
                        }
                        AmendField::AuthorEmail => {
                            let mut email = state.amend_author_email.clone();
                            email.push(c);
                            Some(Action::SetAmendAuthorEmail(email))
                        }
                    }
                }
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_branch_create_mode(event: InputEvent, _state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::CancelBranchCreate),
                Enter => Some(Action::BranchSubmit),
                Backspace => Some(Action::BranchInputBackspace),
                Char(c) => Some(Action::BranchInputChar(c)),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_stash_create_mode(event: InputEvent, _state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::CancelStashCreate),
                Enter => Some(Action::StashSubmit),
                Backspace => Some(Action::StashInputBackspace),
                Char(c) => Some(Action::StashInputChar(c)),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_op_log(event: InputEvent) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc | Enter | Char('q') => Some(Action::ToggleOpLog),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_merge_log(event: InputEvent) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc | Enter | Char('q') => Some(Action::ToggleMergeLog),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_rebase_todo(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            if state.rebase_todo_editing {
                return Ok(match key.code {
                    Esc => Some(Action::RebaseTodoRewriteLine(state.rebase_todo_selected, state.rebase_todo_edit_buffer.clone())),
                    Enter => Some(Action::RebaseTodoRewriteLine(state.rebase_todo_selected, state.rebase_todo_edit_buffer.clone())),
                    Backspace => {
                        let mut buf = state.rebase_todo_edit_buffer.clone();
                        buf.pop();
                        Some(Action::RebaseTodoEditBuffer(buf))
                    }
                    Char(c) => {
                        let mut buf = state.rebase_todo_edit_buffer.clone();
                        buf.push(c);
                        Some(Action::RebaseTodoEditBuffer(buf))
                    }
                    _ => None,
                });
            }
            return Ok(match key.code {
                Esc => Some(Action::HideRebaseTodo),
                Up | Char('k') => Some(Action::RebaseTodoUp),
                Down | Char('j') => Some(Action::RebaseTodoDown),
                Enter => Some(Action::StartRebaseTodoEdit(
                    state.rebase_todo_selected,
                    state.rebase_todo
                        .get(state.rebase_todo_selected)
                        .cloned()
                        .unwrap_or_default(),
                )),
                Char('c') => Some(Action::RebaseContinue),
                Char('a') => Some(Action::RebaseAbort),
                Char('x') => Some(Action::RebaseSkip),
                Char('o') => Some(Action::OpenRebaseTodoInEditor),
                Char('p') => Some(Action::RebaseTodoToggleKind(state.rebase_todo_selected, "pick".into())),
                Char('e') => Some(Action::RebaseTodoToggleKind(state.rebase_todo_selected, "edit".into())),
                Char('s') => Some(Action::RebaseTodoToggleKind(state.rebase_todo_selected, "squash".into())),
                Char('f') => Some(Action::RebaseTodoToggleKind(state.rebase_todo_selected, "fixup".into())),
                Char('d') => Some(Action::RebaseTodoToggleKind(state.rebase_todo_selected, "drop".into())),
                Char('w') => Some(Action::RebaseTodoToggleKind(state.rebase_todo_selected, "reword".into())),
                Char('S') => Some(Action::SaveRebaseTodo),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_rebase_builder(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::RebaseCancel),
                Enter => Some(Action::RebaseSaveAndRun),
                Char('j') | Down => Some(Action::RebaseNext),
                Char('k') | Up => Some(Action::RebasePrev),
                Char('[') => Some(Action::RebaseMoveUp),
                Char(']') => Some(Action::RebaseMoveDown),
                Left | Right => Some(Action::RebaseCycleAction),
                Char('p') => Some(Action::RebaseSetAction(crate::app::state::RebaseAction::Pick)),
                Char('r') => Some(Action::RebaseSetAction(crate::app::state::RebaseAction::Reword)),
                Char('e') => Some(Action::RebaseSetAction(crate::app::state::RebaseAction::Edit)),
                Char('s') => Some(Action::RebaseSetAction(crate::app::state::RebaseAction::Squash)),
                Char('f') => Some(Action::RebaseSetAction(crate::app::state::RebaseAction::Fixup)),
                Char('d') => Some(Action::RebaseSetAction(crate::app::state::RebaseAction::Drop)),
                Char('m') => {
                    // Open reword modal prefilled with current commit message (first reword entry) or empty.
                    let msg = state
                        .rebase_entries
                        .iter()
                        .find(|e| matches!(e.action, crate::app::state::RebaseAction::Reword))
                        .map(|e| e.message.clone())
                        .unwrap_or_default();
                    Some(Action::OpenRewordModal(msg))
                }
                Char('A') => Some(Action::RebaseAbortFromBuilder),
                Char('b') => state
                    .rebase_entries
                    .get(state.rebase_cursor)
                    .map(|entry| Action::RebaseSetBase(entry.hash.clone())),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_reword_input(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    use crate::app::state::RewordField::*;

    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;

            // Get the current buffer based on focused field
            let mut buf = match state.reword_focus_field {
                Message => state.reword_message.clone().unwrap_or_default(),
                AuthorName => state.reword_author_name.clone().unwrap_or_default(),
                AuthorEmail => state.reword_author_email.clone().unwrap_or_default(),
            };

            return Ok(match key.code {
                Esc => Some(Action::CloseRewordModal),
                Enter => {
                    // Get the current message (always required)
                    let message = match state.reword_focus_field {
                        Message => buf,
                        _ => state.reword_message.clone().unwrap_or_default(),
                    };
                    if message.trim().is_empty() {
                        Some(Action::SetStatusError(Some("Reword message cannot be empty".into())))
                    } else {
                        // Save and close on Enter
                        Some(Action::SaveAndCloseReword(message))
                    }
                }
                Backspace => {
                    if !buf.is_empty() {
                        buf.pop();
                        match state.reword_focus_field {
                            Message => Some(Action::SetRewordMessage(buf)),
                            AuthorName => Some(Action::SetRewordAuthorName(buf)),
                            AuthorEmail => Some(Action::SetRewordAuthorEmail(buf)),
                        }
                    } else {
                        // Can't backspace empty field, do nothing
                        None
                    }
                }
                // Ctrl+m focuses message field
                Char('m') if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) => {
                    Some(Action::SetRewordFocus(Message))
                }
                // Ctrl+n focuses and clears author name field
                Char('n') if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) => {
                    Some(Action::FocusAndClearRewordAuthorName)
                }
                // Ctrl+e focuses and clears author email field
                Char('e') if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) => {
                    Some(Action::FocusAndClearRewordAuthorEmail)
                }
                Char(c) => {
                    buf.push(c);
                    match state.reword_focus_field {
                        Message => Some(Action::SetRewordMessage(buf)),
                        AuthorName => Some(Action::SetRewordAuthorName(buf)),
                        AuthorEmail => Some(Action::SetRewordAuthorEmail(buf)),
                    }
                }
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_edit_input(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    use crate::app::state::RewordField::*;

    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;

            // Get the current buffer based on focused field
            let mut buf = match state.edit_focus_field {
                Message => state.edit_message.clone().unwrap_or_default(),
                AuthorName => state.edit_author_name.clone().unwrap_or_default(),
                AuthorEmail => state.edit_author_email.clone().unwrap_or_default(),
            };

            return Ok(match key.code {
                Esc => Some(Action::CloseEditModal),
                Enter => {
                    // Get the current message (always required)
                    let message = match state.edit_focus_field {
                        Message => buf,
                        _ => state.edit_message.clone().unwrap_or_default(),
                    };
                    if message.trim().is_empty() {
                        Some(Action::SetStatusError(Some("Edit message cannot be empty".into())))
                    } else {
                        // Save and close on Enter
                        Some(Action::SaveAndCloseEdit(message))
                    }
                }
                Backspace => {
                    if !buf.is_empty() {
                        buf.pop();
                        match state.edit_focus_field {
                            Message => Some(Action::SetEditMessage(buf)),
                            AuthorName => Some(Action::SetEditAuthorName(buf)),
                            AuthorEmail => Some(Action::SetEditAuthorEmail(buf)),
                        }
                    } else {
                        // Can't backspace empty field, do nothing
                        None
                    }
                }
                // Ctrl+m focuses message field
                Char('m') if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) => {
                    Some(Action::FocusEditMessage)
                }
                // Ctrl+n focuses and clears author name field
                Char('n') if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) => {
                    Some(Action::FocusAndClearEditAuthorName)
                }
                // Ctrl+e focuses and clears author email field
                Char('e') if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) => {
                    Some(Action::FocusAndClearEditAuthorEmail)
                }
                Char(c) => {
                    buf.push(c);
                    match state.edit_focus_field {
                        Message => Some(Action::SetEditMessage(buf)),
                        AuthorName => Some(Action::SetEditAuthorName(buf)),
                        AuthorEmail => Some(Action::SetEditAuthorEmail(buf)),
                    }
                }
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_conflicts_popup(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    let conflicts: Vec<&crate::git::parsers::status::StatusEntry> = state
        .status_entries
        .iter()
        .filter(|e| e.conflict)
        .collect();
    let max_idx = conflicts.len().saturating_sub(1);
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::HideConflictsPopup),
                Up | Char('k') => Some(Action::ConflictsPopupUp),
                Down | Char('j') => Some(Action::ConflictsPopupDown),
                Enter | Right => {
                    let idx = state.conflicts_popup_selected.min(max_idx);
                    let path = conflicts.get(idx).map(|e| e.path.clone());
                    path.map(Action::SelectConflict)
                }
                Char('o') => {
                    let idx = state.conflicts_popup_selected.min(max_idx);
                    let path = conflicts.get(idx).map(|e| e.path.clone());
                    path.map(Action::OpenConflictInEditor)
                }
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_conflicts_guided(event: InputEvent, _state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::HideConflictsGuided),
                Up | Char('k') => Some(Action::ConflictsGuidedUp),
                Down | Char('j') => Some(Action::ConflictsGuidedDown),
                Enter | Char('o') => Some(Action::OpenGuidedConflictInEditor),
                Char('c') => Some(Action::RebaseContinue),
                Char('a') => Some(Action::RebaseAbort),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_pr_helper(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    let prs = &state.pr_list;
    let max_idx = prs.len().saturating_sub(1);
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::HidePrHelper),
                Up | Char('k') => Some(Action::PrHelperUp),
                Down | Char('j') => Some(Action::PrHelperDown),
                Enter => prs
                    .get(state.pr_selected.min(max_idx))
                    .map(|pr| Action::CheckoutPr(pr.number.clone())),
                Char('o') => prs
                    .get(state.pr_selected.min(max_idx))
                    .map(|pr| Action::OpenPrInBrowser(pr.number.clone())),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_theme_picker(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            match key.code {
                Esc => {
                    return Ok(Some(Action::ThemePreviewCancel));
                }
                Char('q') => {
                    return Ok(Some(Action::ThemePreviewCancel));
                }
                Up | Char('k') => {
                    if state.theme_picker_selected > 0 {
                        let target = state.theme_picker_selected - 1;
                        if let Some(name) = state.available_themes.get(target) {
                            return Ok(Some(Action::ThemePreviewSet(
                                target,
                                Box::new(config::load_theme_by_name(name)),
                            )));
                        }
                    }
                }
                Down | Char('j') => {
                    let max_idx = state.available_themes.len().saturating_sub(1);
                    if state.theme_picker_selected < max_idx {
                        let target = state.theme_picker_selected + 1;
                        if let Some(name) = state.available_themes.get(target) {
                            return Ok(Some(Action::ThemePreviewSet(
                                target,
                                Box::new(config::load_theme_by_name(name)),
                            )));
                        }
                    }
                }
                Enter => {
                    let max_idx = state.available_themes.len().saturating_sub(1);
                    let selected = state.theme_picker_selected.min(max_idx);
                    let name = state.available_themes.get(selected).cloned();
                    if let Some(n) = name {
                        return Ok(Some(Action::ApplyTheme(n)));
                    }
                    return Ok(Some(Action::ThemePreviewCancel));
                }
                _ => {}
            }
        }
    }
    Ok(None)
}

fn handle_diff_focus(event: InputEvent) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc | Left => Some(Action::FocusStatus),
                Char('h') => Some(Action::FocusStatus),
                Up | Char('k') | Char('[') | PageUp => Some(Action::DetailScrollUp),
                Down | Char('j') | Char(']') | PageDown => Some(Action::DetailScrollDown),
                Char('<') => Some(Action::DetailScrollLeft),
                Char('>') => Some(Action::DetailScrollRight),
                Home => Some(Action::DetailScrollReset),
                _ => None,
            });
        }
    }
    Ok(None)
}

#[allow(dead_code)]
#[deprecated(note = "Command palette now handled by palette::PaletteHandler. This function kept for backward compatibility only.")]
fn handle_command_palette(_event: InputEvent, _state: &AppState, _manager: &ComponentManager) -> Result<Option<Action>, ComponentError> {
    // Old command palette handler - no longer used
    // New system handles commands via ComponentManager::handle_event -> palette::PaletteHandler
    Ok(None)
}

fn handle_merge_base_picker(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            return Ok(match key.code {
                Esc => Some(Action::HideMergeBasePicker),
                Up | Char('k') => Some(Action::MergeBaseUp),
                Down | Char('j') => Some(Action::MergeBaseDown),
                Enter => {
                    let idx = state.merge_base_selected.min(state.merge_base_candidates.len().saturating_sub(1));
                    let name = state.merge_base_candidates.get(idx).cloned();
                    name.map(Action::ApplyMergeBase)
                }
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_help(event: InputEvent, _state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            use crossterm::event::KeyModifiers;
            return Ok(match key.code {
                Char('q') => Some(Action::Quit),
                Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => Some(Action::Quit),
                Char(':') => Some(Action::ShowPalette),
                Up | Char('k') => Some(Action::HelpUp),
                Down | Char('j') => Some(Action::HelpDown),
                Esc | Char('h') => Some(Action::ToggleHelp),
                _ => None,
            });
        }
    }
    Ok(None)
}

fn handle_log_action_menu(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    if let InputEvent::Key(key) = &event {
        if key.kind == crossterm::event::KeyEventKind::Press {
            use crossterm::event::KeyCode::*;
            match key.code {
                Esc => {
                    return Ok(Some(Action::HideLogActionMenu));
                }
                Up | Char('k') => {
                    return Ok(Some(Action::LogActionMenuUp));
                }
                Down | Char('j') => {
                    return Ok(Some(Action::LogActionMenuDown));
                }
                Enter => {
                    // Get available actions for this commit
                    let actions = get_available_log_actions(state);
                    if let Some(action) = actions.get(state.log_action_selected) {
                        return Ok(Some(Action::ExecuteLogAction(action.clone())));
                    }
                }
                _ => {}
            }
        }
    }
    Ok(None)
}

/// Get available log actions for the selected commit
pub(crate) fn get_available_log_actions(state: &AppState) -> Vec<crate::app::actions::LogAction> {
    use crate::app::actions::LogAction;
    let mut actions = vec![
        LogAction::ShowDetail,
        LogAction::CherryPick,
        LogAction::Revert,
        LogAction::ResetSoft,
        LogAction::ResetMixed,
        LogAction::ResetHard,
        LogAction::CreateBranch,
        LogAction::CreateTag,
    ];
    
    // Check if this is HEAD (first commit in list)
    if let Some(hash) = &state.log_action_commit_hash {
        if let Some(first_commit) = state.commits.first() {
            if first_commit.hash == *hash {
                // Insert Amend at position 3 (after ShowDetail, CherryPick, Revert)
                actions.insert(3, LogAction::Amend);
            }
        }
    }
    
    actions
}

fn handle_active_component(event: InputEvent, state: &AppState, manager: &mut ComponentManager) -> Result<Option<Action>, ComponentError> {
    if let Some(component) = manager.active_mut() {
        if let Some(action) = component.handle_event(event, state)? {
            return Ok(Some(action));
        }
    }
    Ok(None)
}

fn handle_global_keys(event: InputEvent, state: &AppState) -> Result<Option<Action>, ComponentError> {
    match event {
        InputEvent::Key(key) if key.kind == crossterm::event::KeyEventKind::Press => {
            match key.code {
                crossterm::event::KeyCode::Char('q') => {
                    Ok(Some(Action::Quit))
                }
                crossterm::event::KeyCode::Char('c')
                    if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL) =>
                {
                    Ok(Some(Action::Quit))
                }
                crossterm::event::KeyCode::Char('L') => {
                    Ok(Some(Action::LoadFullDiff))
                }
                crossterm::event::KeyCode::Char('l') => {
                    Ok(Some(Action::LoadFullDiff))
                }
                crossterm::event::KeyCode::Char('h') => {
                    Ok(Some(Action::ToggleHelp))
                }
                crossterm::event::KeyCode::Char('t') => {
                    // Show theme picker when 't' is pressed (not in palette mode)
                    if !state.command_palette {
                        Ok(Some(Action::ShowThemePicker))
                    } else {
                        Ok(None)
                    }
                }
                crossterm::event::KeyCode::Right => {
                    Ok(Some(Action::FocusDiff))
                }
                crossterm::event::KeyCode::Char(':') => {
                    Ok(Some(Action::ShowPalette))
                }
                crossterm::event::KeyCode::Tab => {
                    Ok(Some(Action::FocusNext))
                }
                crossterm::event::KeyCode::BackTab => {
                    Ok(Some(Action::FocusPrev))
                }
                // Command shortcuts are now handled by ShortcutHandler (supports multi-character)
                // Only navigation and special keys remain here
                _ => Ok(None),
            }
        }
        _ => Ok(None),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};

    fn key_event(code: KeyCode) -> InputEvent {
        InputEvent::Key(KeyEvent {
            code,
            modifiers: KeyModifiers::NONE,
            kind: KeyEventKind::Press,
            state: KeyEventState::NONE,
        })
    }

    fn state_with_menu(hash: &str) -> AppState {
        let mut state = AppState::new();
        state.log_action_menu = true;
        state.log_action_commit_hash = Some(hash.to_string());
        state
    }

    #[test]
    fn log_action_menu_routes_navigation_keys() {
        let state = state_with_menu("abcd");
        let action = handle_log_action_menu(key_event(KeyCode::Char('j')), &state)
            .unwrap()
            .unwrap();
        assert!(matches!(action, Action::LogActionMenuDown));

        let action = handle_log_action_menu(key_event(KeyCode::Char('k')), &state)
            .unwrap()
            .unwrap();
        assert!(matches!(action, Action::LogActionMenuUp));
    }

    #[test]
    fn log_action_menu_routes_enter_to_execute() {
        let state = state_with_menu("abcd");
        let action = handle_log_action_menu(key_event(KeyCode::Enter), &state)
            .unwrap()
            .unwrap();
        assert!(matches!(action, Action::ExecuteLogAction(_)));
    }

    #[test]
    fn log_action_menu_routes_esc_to_hide() {
        let state = state_with_menu("abcd");
        let action = handle_log_action_menu(key_event(KeyCode::Esc), &state)
            .unwrap()
            .unwrap();
        assert!(matches!(action, Action::HideLogActionMenu));
    }
}