use super::*;
use ratatui::crossterm::event::KeyModifiers;

use super::super::types::{OverlayEvent, OverlaySubmission};
use crate::ui::tui::session::modal::{ModalKeyModifiers, ModalListKeyResult};

pub(super) fn handle_paste(session: &mut Session, content: &str) {
    if session.input_enabled {
        session.insert_paste_text(content);
        session.mark_dirty();
    } else if let Some(modal) = session.modal_state_mut()
        && let (Some(list), Some(search)) = (modal.list.as_mut(), modal.search.as_mut())
    {
        search.insert(content);
        list.apply_search(&search.query);
        session.mark_dirty();
    } else if let Some(wizard) = session.wizard_overlay_mut()
        && let Some(search) = wizard.search.as_mut()
    {
        search.insert(content);
        if let Some(step) = wizard.steps.get_mut(wizard.current_step) {
            step.list.apply_search(&search.query);
        }
        session.mark_dirty();
    }
}

fn copy_selected_input_if_requested(
    session: &mut Session,
    key: &KeyEvent,
    has_command: bool,
) -> bool {
    let is_copy_shortcut = if has_command {
        matches!(key.code, KeyCode::Char('c') | KeyCode::Char('C'))
    } else {
        match key.code {
            KeyCode::Char('c') | KeyCode::Char('C') => {
                key.modifiers.contains(KeyModifiers::CONTROL)
            }
            KeyCode::Char('\u{3}') => true,
            _ => false,
        }
    };

    if !is_copy_shortcut {
        return false;
    }

    if session.copy_input_selection_to_clipboard() {
        session.mark_dirty();
        return true;
    }

    false
}

fn handle_interrupt(session: &mut Session) -> Option<InlineEvent> {
    if session.mouse_selection.has_selection {
        session.mouse_selection.request_copy();
        session.mark_dirty();
        return None;
    }
    if session.has_active_overlay() {
        session.close_overlay();
    }
    session.mark_dirty();
    Some(InlineEvent::Interrupt)
}

pub(super) fn process_key(session: &mut Session, key: KeyEvent) -> Option<InlineEvent> {
    let modifiers = key.modifiers;
    let has_control = modifiers.contains(KeyModifiers::CONTROL);
    let has_shift = modifiers.contains(KeyModifiers::SHIFT);
    let raw_alt = modifiers.contains(KeyModifiers::ALT);
    let raw_meta = modifiers.contains(KeyModifiers::META);
    let has_super = modifiers.contains(KeyModifiers::SUPER);
    // Command key detection: prioritize Command/Super over Alt
    // On macOS: Command = SUPER, on some terminals Alt = META
    let has_command = has_super || raw_meta;
    let has_alt = raw_alt && !has_command;

    // Allow copy-to-clipboard even when a modal is active so users can
    // copy selected transcript text without dismissing the overlay first.
    // The modal's own key handler below will still consume Ctrl+C/Esc to
    // close the overlay when no text is selected.
    if copy_selected_input_if_requested(session, &key, has_command) {
        return None;
    }

    if let Some(modal) = session.modal_state_mut() {
        let modal_modifiers = ModalKeyModifiers {
            control: has_control,
            alt: has_alt,
            command: has_command,
        };

        if let Some(action) = modal.hotkey_action(&key, modal_modifiers) {
            session.close_overlay();
            session.mark_dirty();
            return Some(InlineEvent::Overlay(OverlayEvent::Submitted(
                OverlaySubmission::Hotkey(action),
            )));
        }

        let result = modal.handle_list_key_event(&key, modal_modifiers);

        match result {
            ModalListKeyResult::Redraw => {
                session.mark_dirty();
                return None;
            }
            ModalListKeyResult::Emit(event) => {
                session.mark_dirty();
                return Some(event);
            }
            ModalListKeyResult::HandledNoRedraw => {
                return None;
            }
            ModalListKeyResult::Submit(event) | ModalListKeyResult::Cancel(event) => {
                session.close_overlay();
                return Some(event);
            }
            ModalListKeyResult::NotHandled => {}
        }
    }

    if let Some(wizard) = session.wizard_overlay_mut() {
        let result = wizard.handle_key_event(
            &key,
            ModalKeyModifiers {
                control: has_control,
                alt: has_alt,
                command: has_command,
            },
        );

        match result {
            ModalListKeyResult::Redraw => {
                session.mark_dirty();
                return None;
            }
            ModalListKeyResult::Emit(event) => {
                session.mark_dirty();
                return Some(event);
            }
            ModalListKeyResult::HandledNoRedraw => {
                return None;
            }
            ModalListKeyResult::Submit(event) => {
                session.close_overlay();
                return Some(event);
            }
            ModalListKeyResult::Cancel(event) => {
                session.close_overlay();
                return Some(event);
            }
            ModalListKeyResult::NotHandled => {}
        }
    }

    if session.handle_vim_key(&key) {
        return None;
    }

    // Legacy reverse search handling (kept for backward compatibility)
    // Handle reverse search (Ctrl+R) - disabled in favor of history picker
    // if has_control && matches!(key.code, KeyCode::Char('r') | KeyCode::Char('R')) {
    //     if !session.reverse_search_state.active {
    //         session.reverse_search_state.start_search(
    //             &session.input_manager,
    //             &session.input_manager.history_texts(),
    //         );
    //         session.mark_dirty();
    //         return None;
    //     }
    // }

    // Handle reverse search if active (legacy)
    if session.reverse_search_state.active {
        // Get history first to avoid borrow conflicts
        let history = session.input_manager.history_texts();
        let handled = reverse_search::handle_reverse_search_key(
            &key,
            &mut session.reverse_search_state,
            &mut session.input_manager,
            &history,
        );
        if handled {
            session.mark_dirty();
            return None;
        }
    }

    match key.code {
        KeyCode::Char('c') | KeyCode::Char('C') if has_control => handle_interrupt(session),
        KeyCode::Char('\u{3}') => handle_interrupt(session),
        KeyCode::Char('d') if has_control => {
            session.mark_dirty();
            Some(InlineEvent::Exit)
        }
        KeyCode::Char('b') if has_control => {
            // Ctrl+B - Background current operation or move to background
            session.mark_dirty();
            Some(InlineEvent::BackgroundOperation)
        }
        KeyCode::Char('m') | KeyCode::Char('M') if has_control && !has_alt && !has_command => {
            session.mark_dirty();
            Some(InlineEvent::Submit("/model".to_string()))
        }
        KeyCode::Char('a') | KeyCode::Char('A') if has_control && !has_command && !has_alt => {
            if session.input_enabled {
                session.move_to_start();
                session.mark_dirty();
            }
            None
        }
        KeyCode::Char('e') | KeyCode::Char('E') if has_control && !has_command && !has_alt => {
            if !session.input_enabled {
                None
            } else if session.input_manager.content().is_empty() {
                session.mark_dirty();
                Some(InlineEvent::LaunchEditor)
            } else {
                session.move_to_end();
                session.mark_dirty();
                None
            }
        }
        KeyCode::Char('w') | KeyCode::Char('W') if has_control && !has_command && !has_alt => {
            if session.input_enabled {
                session.delete_word_backward();
                session.mark_dirty();
            }
            None
        }
        KeyCode::Char('u') | KeyCode::Char('U') if has_control && !has_command && !has_alt => {
            if session.input_enabled {
                session.delete_to_start_of_line();
                session.mark_dirty();
            }
            None
        }
        KeyCode::Char('k') | KeyCode::Char('K') if has_control && !has_command && !has_alt => {
            if session.input_enabled {
                session.delete_to_end_of_line();
                session.mark_dirty();
            }
            None
        }
        KeyCode::Char('j') if has_control => {
            // Ctrl+J is a line feed character, insert newline for multiline input
            session.insert_char('\n');
            session.mark_dirty();
            None
        }
        KeyCode::Char('l') | KeyCode::Char('L') if has_control => {
            session.mark_dirty();
            Some(InlineEvent::Submit("/clear".to_string()))
        }
        KeyCode::BackTab => {
            // Shift+Tab: Toggle editing mode
            session.clear_inline_prompt_suggestion();
            session.mark_dirty();
            Some(InlineEvent::ToggleMode)
        }
        KeyCode::Esc => {
            if session.has_active_overlay() {
                session.close_overlay();
                None
            } else {
                let is_double_escape = session.input_manager.check_escape_double_tap();
                let active_pty_count = session.active_pty_session_count();
                let has_running_activity = session.is_running_activity();

                if has_running_activity || active_pty_count > 0 {
                    session.mark_dirty();
                    if is_double_escape {
                        Some(InlineEvent::Exit)
                    } else {
                        Some(InlineEvent::Interrupt)
                    }
                } else if is_double_escape && !has_running_activity {
                    // Double-escape while idle rewinds to the latest checkpoint.
                    session.mark_dirty();
                    Some(InlineEvent::Submit("/rewind".to_string()))
                } else if !session.input_manager.content().is_empty() {
                    // Single escape with content: clear input
                    command::clear_input(session);
                    session.mark_dirty();
                    None
                } else {
                    // Single escape with no content: cancel
                    session.mark_dirty();
                    Some(InlineEvent::Cancel)
                }
            }
        }
        KeyCode::PageUp => {
            session.scroll_page_up();
            session.mark_dirty();
            Some(InlineEvent::ScrollPageUp)
        }
        KeyCode::PageDown => {
            session.scroll_page_down();
            session.mark_dirty();
            Some(InlineEvent::ScrollPageDown)
        }
        KeyCode::Up => {
            let edit_queue_modifier = has_alt || (raw_meta && !has_super);
            if !terminal_capabilities::queued_input_edit_uses_shift_left()
                && edit_queue_modifier
                && !session.queued_inputs.is_empty()
            {
                if let Some(latest) = session.pop_latest_queued_input() {
                    session.clear_inline_prompt_suggestion();
                    session.input_manager.set_content(latest);
                    session.input_compact_mode = session.input_compact_placeholder().is_some();
                    session.scroll_manager.set_offset(0);
                }
                session.mark_dirty();
                Some(InlineEvent::EditQueue)
            } else if session.navigate_history_previous() {
                session.mark_dirty();
                Some(InlineEvent::HistoryPrevious)
            } else {
                None
            }
        }
        KeyCode::Down => {
            if session.navigate_history_next() {
                session.clear_inline_prompt_suggestion();
                session.mark_dirty();
                Some(InlineEvent::HistoryNext)
            } else {
                None
            }
        }
        KeyCode::Enter => {
            if !session.input_enabled {
                return None;
            }

            // No slash command palette in core session.

            if !has_control
                && !has_shift
                && !has_alt
                && session.input_manager.content().trim().is_empty()
                && session.active_pty_session_count() > 0
            {
                session.mark_dirty();
                return Some(InlineEvent::Submit("/jobs".to_string()));
            }

            // Check for backslash + Enter quick escape (insert newline without submitting)
            if !has_control && session.input_manager.content().ends_with('\\') {
                // Remove the backslash and insert a newline
                let mut content = session.input_manager.content().to_string();
                content.pop(); // Remove the backslash
                content.push('\n');
                session.input_manager.set_content(content);
                session.mark_dirty();
                return None;
            }

            if has_control {
                let Some(submitted) = take_submitted_input(session) else {
                    session.mark_dirty();
                    return if session.is_running_activity() {
                        None
                    } else {
                        Some(InlineEvent::ProcessLatestQueued)
                    };
                };
                session.mark_dirty();

                return if session.is_running_activity() {
                    Some(InlineEvent::Steer(submitted))
                } else {
                    Some(InlineEvent::Submit(submitted))
                };
            }

            // Check for multiline input options (Shift/Alt)
            if has_shift || has_alt {
                // Insert newline for multiline input
                session.insert_char('\n');
                session.mark_dirty();
                return None;
            }

            let Some(submitted) = take_submitted_input(session) else {
                session.mark_dirty();
                return None;
            };

            session.mark_dirty();

            // If a turn is actively running, queue the message so it starts immediately after
            // the current turn completes. Otherwise submit directly so the turn starts now.
            if session.is_running_activity() {
                session.push_queued_input(submitted.clone());
                Some(InlineEvent::QueueSubmit(submitted))
            } else {
                Some(InlineEvent::Submit(submitted))
            }
        }
        KeyCode::Tab => {
            if !session.input_enabled {
                return None;
            }

            if session.accept_inline_prompt_suggestion() {
                return None;
            }

            let Some(submitted) = take_submitted_input(session) else {
                session.mark_dirty();
                return None;
            };
            session.push_queued_input(submitted.clone());
            session.mark_dirty();
            Some(InlineEvent::QueueSubmit(submitted))
        }
        KeyCode::Backspace => {
            if session.input_enabled {
                if has_alt {
                    session.delete_word_backward();
                } else if has_command {
                    session.delete_to_start_of_line();
                } else {
                    session.delete_char();
                }
                session.mark_dirty();
            }
            None
        }
        KeyCode::Delete => {
            if session.input_enabled {
                if has_alt {
                    session.delete_word_backward();
                } else if has_command {
                    session.delete_to_end_of_line();
                } else {
                    session.delete_char_forward();
                }
                session.mark_dirty();
            }
            None
        }
        KeyCode::Left => {
            if session.input_enabled {
                let tmux_queue_edit = has_shift
                    && !has_control
                    && !has_command
                    && !has_alt
                    && terminal_capabilities::queued_input_edit_uses_shift_left()
                    && !session.queued_inputs.is_empty();
                if tmux_queue_edit {
                    if let Some(latest) = session.pop_latest_queued_input() {
                        session.clear_inline_prompt_suggestion();
                        session.input_manager.set_content(latest);
                        session.input_compact_mode = session.input_compact_placeholder().is_some();
                        session.scroll_manager.set_offset(0);
                    }
                    session.mark_dirty();
                    return Some(InlineEvent::EditQueue);
                }

                session.clear_inline_prompt_suggestion();
                if has_shift && has_command {
                    session.select_to_start();
                } else if has_shift {
                    session.select_left();
                } else if has_command {
                    session.move_to_start();
                } else if has_alt {
                    session.move_left_word();
                } else {
                    session.move_left();
                }
                session.mark_dirty();
            }
            None
        }
        KeyCode::Right => {
            if session.input_enabled {
                session.clear_inline_prompt_suggestion();
                if has_shift && has_command {
                    session.select_to_end();
                } else if has_shift {
                    session.select_right();
                } else if has_command {
                    session.move_to_end();
                } else if has_alt {
                    session.move_right_word();
                } else {
                    session.move_right();
                }
                session.mark_dirty();
            }
            None // Right arrow never triggers any event, including editor launch
        }
        KeyCode::Home => {
            if session.input_enabled {
                session.clear_inline_prompt_suggestion();
                if has_shift {
                    session.select_to_start();
                } else {
                    session.move_to_start();
                }
                session.mark_dirty();
            }
            None
        }
        KeyCode::End => {
            if session.input_enabled {
                session.clear_inline_prompt_suggestion();
                if has_shift {
                    session.select_to_end();
                } else {
                    session.move_to_end();
                }
                session.mark_dirty();
            }
            None
        }
        KeyCode::Char('t') | KeyCode::Char('T') if has_control => {
            session.toggle_logs();
            None
        }
        KeyCode::Char(ch) => {
            if !session.input_enabled {
                return None;
            }

            if has_alt && matches!(ch, 'p' | 'P') {
                session.clear_inline_prompt_suggestion();
                session.mark_dirty();
                return Some(InlineEvent::RequestInlinePromptSuggestion(
                    session.input_manager.content().to_string(),
                ));
            }

            if ch == '?'
                && !has_control
                && !has_alt
                && !has_command
                && session.input_manager.content().is_empty()
            {
                session.show_modal("Keyboard Shortcuts".to_string(), quick_help_lines(), None);
                return None;
            }

            if ch == '\t' {
                if session.accept_inline_prompt_suggestion() {
                    return None;
                }
                let Some(submitted) = take_submitted_input(session) else {
                    session.mark_dirty();
                    return None;
                };
                session.push_queued_input(submitted.clone());
                session.mark_dirty();
                return Some(InlineEvent::QueueSubmit(submitted));
            }

            if has_command {
                match ch {
                    'a' | 'A' => {
                        session.move_to_start();
                        session.mark_dirty();
                        return None;
                    }
                    'e' | 'E' => {
                        session.move_to_end();
                        session.mark_dirty();
                        return None;
                    }
                    _ => {}
                }
            }

            if has_alt {
                match ch {
                    'b' | 'B' => {
                        session.move_left_word();
                        session.mark_dirty();
                    }
                    'f' | 'F' => {
                        session.move_right_word();
                        session.mark_dirty();
                    }
                    _ => {}
                }
                return None;
            }

            if !has_control {
                session.insert_char(ch);
                session.mark_dirty();
            }
            None
        }
        _ => None,
    }
}

fn quick_help_lines() -> Vec<String> {
    vec![
        "Enter queues; Tab queues or accepts an inline suggestion.".to_string(),
        "Alt+P: Generate an inline prompt suggestion.".to_string(),
        "Ctrl+Enter: Run now while idle, or steer the active task.".to_string(),
        "Shift+Enter: Insert a newline.".to_string(),
        "/config: Toggle Vim-style prompt editing via Editor mode.".to_string(),
        "Ctrl+A / Ctrl+E: Move to start/end of line.".to_string(),
        "Ctrl+W: Delete previous word.".to_string(),
        "Ctrl+U / Ctrl+K: Delete to start/end of line.".to_string(),
        "Ctrl+I or Ctrl+/: Toggle inline lists.".to_string(),
        "Ctrl+M: Open the model picker.".to_string(),
        "Alt+Left / Alt+Right: Move by word.".to_string(),
        "Ctrl+Z (Unix): Suspend VT Code; use `fg` to resume.".to_string(),
        "Esc: Close this overlay.".to_string(),
    ]
}

fn take_submitted_input(session: &mut Session) -> Option<String> {
    let submitted = session.input_manager.content().to_owned();
    let submitted_entry = session.input_manager.current_history_entry();
    clear_submitted_input(session);

    if submitted.trim().is_empty() {
        return None;
    }

    session.remember_submitted_input(submitted_entry);
    Some(submitted)
}

fn clear_submitted_input(session: &mut Session) {
    session.input_manager.clear();
    session.clear_suggested_prompt_state();
    session.clear_inline_prompt_suggestion();
    session.input_compact_mode = false;
    session.scroll_manager.set_offset(0);
}
