//! Input handling for TUI application.
//!
//! Key event handlers, mouse event handlers, and popup navigation.

use crossterm::event::{
    Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
};

use crate::session::{SessionId, SessionStatus};
use crate::tui::popup::PopupSection;
use crate::tui::tabs::{StatusIndicator, TabItem, find_tab_at_column};

use super::action::AppAction;
use super::state::AppState;
use super::tuiapp::TuiApp;

/// Check if key event is a cancel key (Esc or Ctrl+g)
fn is_cancel_key(key: KeyEvent) -> bool {
    matches!(key.code, KeyCode::Esc)
        || (matches!(key.code, KeyCode::Char('g')) && key.modifiers.contains(KeyModifiers::CONTROL))
}

impl TuiApp {
    /// Handle crossterm event
    pub fn handle_event(&mut self, event: &Event) -> Option<AppAction> {
        match event {
            Event::Key(key) => self.handle_key(*key),
            Event::Mouse(mouse) => self.handle_mouse(*mouse),
            Event::Resize(cols, rows) => Some(AppAction::ResizeTerminal(*rows, *cols)),
            _ => None,
        }
    }

    /// Handle key event
    pub fn handle_key(&mut self, key: KeyEvent) -> Option<AppAction> {
        match self.state {
            AppState::Normal => self.handle_key_normal(key),
            AppState::WorkspacePopup => self.handle_key_workspace_popup(key),
            AppState::ConfirmQuit => self.handle_key_confirm_quit(key),
            AppState::ErrorPopup { .. } => self.handle_key_error_popup(key),
            AppState::SessionTerminatedPopup { session_id, .. } => {
                self.handle_key_session_terminated_popup(key, session_id)
            }
            AppState::IssueLoading { .. } => {
                // During loading, only Esc/Ctrl-g cancels
                self.handle_key_issue_loading(key)
            }
            AppState::ActionSelectPopup { .. } => self.handle_key_action_select_popup(key),
            AppState::ConfirmPermissions { .. } => self.handle_key_confirm_permissions(key),
        }
    }

    /// Handle key event in issue loading state
    #[allow(clippy::unused_self)]
    fn handle_key_issue_loading(&self, key: KeyEvent) -> Option<AppAction> {
        is_cancel_key(key).then_some(AppAction::CancelIssueFlow)
    }

    /// Handle key event in action select popup
    fn handle_key_action_select_popup(&mut self, key: KeyEvent) -> Option<AppAction> {
        if is_cancel_key(key) {
            return Some(AppAction::CancelIssueFlow);
        }
        match key.code {
            KeyCode::Up | KeyCode::Char('k') => Some(AppAction::SelectPrev),
            KeyCode::Down | KeyCode::Char('j') => Some(AppAction::SelectNext),
            KeyCode::Char('p') if key.modifiers.contains(KeyModifiers::CONTROL) => {
                Some(AppAction::SelectPrev)
            }
            KeyCode::Char('n') if key.modifiers.contains(KeyModifiers::CONTROL) => {
                Some(AppAction::SelectNext)
            }
            KeyCode::Enter => {
                if let AppState::ActionSelectPopup { ref choices, .. } = self.state
                    && let Some(idx) = self.action_select_state.selected()
                    && idx < choices.len()
                {
                    return Some(AppAction::SelectActionChoice { index: idx });
                }
                None
            }
            KeyCode::Char('m') if key.modifiers.contains(KeyModifiers::CONTROL) => {
                if let AppState::ActionSelectPopup { ref choices, .. } = self.state
                    && let Some(idx) = self.action_select_state.selected()
                    && idx < choices.len()
                {
                    return Some(AppAction::SelectActionChoice { index: idx });
                }
                None
            }
            _ => None,
        }
    }

    /// Handle key event in confirm permissions popup
    fn handle_key_confirm_permissions(&mut self, key: KeyEvent) -> Option<AppAction> {
        if is_cancel_key(key) || matches!(key.code, KeyCode::Char('n' | 'N')) {
            return Some(AppAction::CancelIssueFlow);
        }
        match key.code {
            KeyCode::Char('y' | 'Y') => Some(AppAction::ConfirmDangerousPermissions),
            KeyCode::Left | KeyCode::Right | KeyCode::Tab => {
                Some(AppAction::TogglePermissionsChoice)
            }
            KeyCode::Enter | KeyCode::Char('m')
                if key.modifiers.contains(KeyModifiers::CONTROL) =>
            {
                if let AppState::ConfirmPermissions { selected_yes, .. } = self.state
                    && selected_yes
                {
                    return Some(AppAction::ConfirmDangerousPermissions);
                }
                Some(AppAction::CancelIssueFlow)
            }
            _ => None,
        }
    }

    /// Handle key event in session terminated popup
    fn handle_key_session_terminated_popup(
        &mut self,
        key: KeyEvent,
        session_id: SessionId,
    ) -> Option<AppAction> {
        match key.code {
            KeyCode::Char('c' | 'C') => {
                self.state = AppState::Normal;
                Some(AppAction::CloseSession { id: session_id })
            }
            KeyCode::Char('n' | 'N') | KeyCode::Esc => {
                self.state = AppState::Normal;
                None
            }
            _ => None,
        }
    }

    /// Handle key event in error popup
    #[allow(clippy::unused_self)]
    fn handle_key_error_popup(&self, key: KeyEvent) -> Option<AppAction> {
        match key.code {
            KeyCode::Enter | KeyCode::Esc => Some(AppAction::DismissError),
            _ => None,
        }
    }

    #[allow(clippy::unused_self)]
    fn handle_key_normal(&mut self, key: KeyEvent) -> Option<AppAction> {
        // Check for Ctrl modifiers first
        if key.modifiers.contains(KeyModifiers::CONTROL) {
            return match key.code {
                // Note: Ctrl-t removed (session creation via WorkspacePopup only)
                KeyCode::Char('w') => Some(AppAction::TerminateCurrentSession),
                KeyCode::Char('n') => Some(AppAction::NextSession),
                KeyCode::Char('p') => Some(AppAction::PrevSession),
                KeyCode::Char('s') => Some(AppAction::ShowWorkspacePopup),
                KeyCode::Char('q') => Some(AppAction::ShowConfirmQuit),
                _ => {
                    // Forward other Ctrl combinations to session
                    if let KeyCode::Char(c) = key.code {
                        // Ctrl+char sends ASCII 1-26 (Ctrl+a=1, Ctrl+b=2, etc.)
                        let ctrl_code = c.to_ascii_lowercase() as u8 - b'a' + 1;
                        Some(AppAction::SendInput(vec![ctrl_code]))
                    } else {
                        None
                    }
                }
            };
        }

        // Forward other keys to session
        match key.code {
            KeyCode::Char(c) => Some(AppAction::SendInput(c.to_string().into_bytes())),
            KeyCode::Enter => Some(AppAction::SendInput(vec![b'\r'])),
            KeyCode::Backspace => Some(AppAction::SendInput(vec![0x7f])),
            KeyCode::Tab => Some(AppAction::SendInput(vec![b'\t'])),
            KeyCode::BackTab => Some(AppAction::SendInput(b"\x1b[Z".to_vec())),
            KeyCode::Esc => Some(AppAction::SendInput(vec![0x1b])),
            KeyCode::Up => Some(AppAction::SendInput(b"\x1b[A".to_vec())),
            KeyCode::Down => Some(AppAction::SendInput(b"\x1b[B".to_vec())),
            KeyCode::Right => Some(AppAction::SendInput(b"\x1b[C".to_vec())),
            KeyCode::Left => Some(AppAction::SendInput(b"\x1b[D".to_vec())),
            KeyCode::Home => Some(AppAction::SendInput(b"\x1b[H".to_vec())),
            KeyCode::End => Some(AppAction::SendInput(b"\x1b[F".to_vec())),
            KeyCode::PageUp => Some(AppAction::Scroll(-10)),
            KeyCode::PageDown => Some(AppAction::Scroll(10)),
            KeyCode::Delete => Some(AppAction::SendInput(b"\x1b[3~".to_vec())),
            _ => None,
        }
    }

    /// Handle key event in workspace popup
    ///
    /// Behavior depends on current popup section (`BranchInput`, `Sessions`, `Worktrees`)
    fn handle_key_workspace_popup(&mut self, key: KeyEvent) -> Option<AppAction> {
        // Global popup keys
        match key.code {
            KeyCode::Esc => return Some(AppAction::HidePopup),
            KeyCode::Tab => return Some(AppAction::NextPopupSection),
            KeyCode::BackTab => return Some(AppAction::PrevPopupSection),
            _ => {}
        }

        // Emacs-style navigation (Ctrl-g/n/p/m)
        if key.modifiers.contains(KeyModifiers::CONTROL) {
            match key.code {
                KeyCode::Char('g') => return Some(AppAction::HidePopup),
                KeyCode::Char('n') => return Some(AppAction::CrossSectionNext),
                KeyCode::Char('p') => return Some(AppAction::CrossSectionPrev),
                KeyCode::Char('m') => return self.handle_enter_for_section(),
                KeyCode::Char('q') => return Some(AppAction::ShowConfirmQuit),
                _ => {}
            }
        }

        // Section-specific keys
        match self.popup_state.section {
            PopupSection::BranchInput => self.handle_key_branch_input(key),
            PopupSection::Sessions => self.handle_key_session_section(key),
            PopupSection::Worktrees => self.handle_key_worktree_section(key),
            PopupSection::Issues => self.handle_key_issue_section(key),
        }
    }

    /// Handle key event in issues section
    fn handle_key_issue_section(&mut self, key: KeyEvent) -> Option<AppAction> {
        match key.code {
            KeyCode::Up => Some(AppAction::SelectPrev),
            KeyCode::Down => Some(AppAction::SelectNext),
            KeyCode::Enter => self
                .selected_issue()
                .map(|i| AppAction::SelectIssue { number: i.number }),
            _ => None,
        }
    }

    /// Handle key event in branch input section
    fn handle_key_branch_input(&mut self, key: KeyEvent) -> Option<AppAction> {
        match key.code {
            KeyCode::Char(c) => Some(AppAction::InputChar(c)),
            KeyCode::Backspace => Some(AppAction::InputBackspace),
            KeyCode::Left => Some(AppAction::InputCursorLeft),
            KeyCode::Right => Some(AppAction::InputCursorRight),
            KeyCode::Enter if !self.popup_state.input.is_empty() => Some(
                AppAction::CreateSessionWithBranch(self.popup_state.input.clone()),
            ),
            _ => None,
        }
    }

    /// Handle key event in sessions section
    #[allow(clippy::unused_self)]
    fn handle_key_session_section(&mut self, key: KeyEvent) -> Option<AppAction> {
        match key.code {
            KeyCode::Down => Some(AppAction::SelectNext),
            KeyCode::Up => Some(AppAction::SelectPrev),
            KeyCode::Enter => Some(AppAction::ConfirmSelection),
            KeyCode::Char('d') => self.selected_session_for_close(),
            _ => None,
        }
    }

    /// Get selected session for close action (only terminated sessions)
    fn selected_session_for_close(&self) -> Option<AppAction> {
        let idx = self.popup_state.session_list.selected()?;
        let session = self.sessions.get(idx)?;
        // Only allow close for terminated sessions
        if matches!(session.status, SessionStatus::Terminated { .. }) {
            Some(AppAction::CloseSession { id: session.id })
        } else {
            None
        }
    }

    /// Handle key event in worktrees section
    fn handle_key_worktree_section(&mut self, key: KeyEvent) -> Option<AppAction> {
        match key.code {
            KeyCode::Down => Some(AppAction::SelectNext),
            KeyCode::Up => Some(AppAction::SelectPrev),
            KeyCode::Enter => self.selected_worktree().map(|w| AppAction::AdoptWorktree {
                path: w.path.clone(),
            }),
            KeyCode::Char('d') => self.selected_worktree().map(|w| AppAction::DeleteWorktree {
                path: w.path.clone(),
            }),
            KeyCode::Char('p') => self.selected_worktree().map(|w| AppAction::PullWorktree {
                path: w.path.clone(),
            }),
            _ => None,
        }
    }

    /// Get selected worktree item (if any)
    pub(super) fn selected_worktree(&self) -> Option<&super::super::popup::WorktreeItem> {
        self.popup_state
            .worktree_list
            .selected()
            .and_then(|idx| self.worktrees.get(idx))
    }

    /// Get selected issue item (if any)
    pub(super) fn selected_issue(&self) -> Option<&super::super::popup::IssueItem> {
        self.popup_state
            .issue_list
            .selected()
            .and_then(|idx| self.issues.get(idx))
    }

    /// Handle Enter for current popup section (Ctrl-m dispatch)
    pub(super) fn handle_enter_for_section(&self) -> Option<AppAction> {
        match self.popup_state.section {
            PopupSection::BranchInput => {
                if self.popup_state.input.is_empty() {
                    None
                } else {
                    Some(AppAction::CreateSessionWithBranch(
                        self.popup_state.input.clone(),
                    ))
                }
            }
            PopupSection::Sessions => Some(AppAction::ConfirmSelection),
            PopupSection::Worktrees => self.selected_worktree().map(|w| AppAction::AdoptWorktree {
                path: w.path.clone(),
            }),
            PopupSection::Issues => self
                .selected_issue()
                .map(|i| AppAction::SelectIssue { number: i.number }),
        }
    }

    #[allow(clippy::unused_self)]
    fn handle_key_confirm_quit(&mut self, key: KeyEvent) -> Option<AppAction> {
        match key.code {
            KeyCode::Esc | KeyCode::Char('n' | 'N') => Some(AppAction::HidePopup),
            KeyCode::Char('y' | 'Y') => Some(AppAction::ConfirmQuit),
            KeyCode::Tab | KeyCode::Left | KeyCode::Right => Some(AppAction::ToggleQuitSelection),
            _ => None,
        }
    }

    /// Handle mouse event
    pub fn handle_mouse(&mut self, mouse: MouseEvent) -> Option<AppAction> {
        match mouse.kind {
            MouseEventKind::Down(MouseButton::Left) => {
                // Check if click is on tab bar (first row)
                if mouse.row == 0 && self.state == AppState::Normal {
                    let tabs: Vec<TabItem> = self
                        .sessions
                        .iter()
                        .map(|s| TabItem::new(&s.name, StatusIndicator::from(&s.status)))
                        .collect();
                    if let Some(idx) = find_tab_at_column(&tabs, mouse.column) {
                        return Some(AppAction::SwitchSession(idx));
                    }
                }
                None
            }
            MouseEventKind::ScrollUp => Some(AppAction::Scroll(-3)),
            MouseEventKind::ScrollDown => Some(AppAction::Scroll(3)),
            _ => None,
        }
    }

    // Navigation methods

    pub(super) fn select_next(&mut self) {
        // Handle ActionSelectPopup state
        if let AppState::ActionSelectPopup { ref choices, .. } = self.state {
            self.action_select_state.select_next(choices.len());
            return;
        }
        match self.popup_state.section {
            PopupSection::Sessions => {
                if self.sessions.is_empty() {
                    return;
                }
                let current = self.popup_state.session_list.selected().unwrap_or(0);
                let next = (current + 1) % self.sessions.len();
                self.popup_state.session_list.select(Some(next));
            }
            PopupSection::Worktrees => {
                if self.worktrees.is_empty() {
                    return;
                }
                let current = self.popup_state.worktree_list.selected().unwrap_or(0);
                let next = (current + 1) % self.worktrees.len();
                self.popup_state.worktree_list.select(Some(next));
            }
            PopupSection::Issues => {
                if self.issues.is_empty() {
                    return;
                }
                let current = self.popup_state.issue_list.selected().unwrap_or(0);
                let next = (current + 1) % self.issues.len();
                self.popup_state.issue_list.select(Some(next));
            }
            PopupSection::BranchInput => {}
        }
    }

    pub(super) fn select_prev(&mut self) {
        // Handle ActionSelectPopup state
        if let AppState::ActionSelectPopup { ref choices, .. } = self.state {
            self.action_select_state.select_prev(choices.len());
            return;
        }
        match self.popup_state.section {
            PopupSection::Sessions => {
                if self.sessions.is_empty() {
                    return;
                }
                let current = self.popup_state.session_list.selected().unwrap_or(0);
                let prev = if current == 0 {
                    self.sessions.len() - 1
                } else {
                    current - 1
                };
                self.popup_state.session_list.select(Some(prev));
            }
            PopupSection::Worktrees => {
                if self.worktrees.is_empty() {
                    return;
                }
                let current = self.popup_state.worktree_list.selected().unwrap_or(0);
                let prev = if current == 0 {
                    self.worktrees.len() - 1
                } else {
                    current - 1
                };
                self.popup_state.worktree_list.select(Some(prev));
            }
            PopupSection::Issues => {
                if self.issues.is_empty() {
                    return;
                }
                let current = self.popup_state.issue_list.selected().unwrap_or(0);
                let prev = if current == 0 {
                    self.issues.len() - 1
                } else {
                    current - 1
                };
                self.popup_state.issue_list.select(Some(prev));
            }
            PopupSection::BranchInput => {}
        }
    }

    /// Cross-section navigation: next item
    ///
    /// Cycle: `BranchInput` → `Sessions[0..n-1]` → `Worktrees[0..m-1]` → `Issues[0..k-1]` → `BranchInput`
    pub(super) fn cross_section_next(&mut self) {
        match self.popup_state.section {
            PopupSection::BranchInput => {
                // BranchInput → Sessions[0] (or next non-empty section)
                if !self.sessions.is_empty() {
                    self.popup_state.section = PopupSection::Sessions;
                    self.popup_state.session_list.select(Some(0));
                } else if !self.worktrees.is_empty() {
                    self.popup_state.section = PopupSection::Worktrees;
                    self.popup_state.worktree_list.select(Some(0));
                } else if !self.issues.is_empty() {
                    self.popup_state.section = PopupSection::Issues;
                    self.popup_state.issue_list.select(Some(0));
                }
            }
            PopupSection::Sessions => {
                let current = self.popup_state.session_list.selected().unwrap_or(0);
                if current + 1 < self.sessions.len() {
                    self.popup_state.session_list.select(Some(current + 1));
                } else if !self.worktrees.is_empty() {
                    self.popup_state.section = PopupSection::Worktrees;
                    self.popup_state.worktree_list.select(Some(0));
                } else if !self.issues.is_empty() {
                    self.popup_state.section = PopupSection::Issues;
                    self.popup_state.issue_list.select(Some(0));
                } else {
                    self.popup_state.section = PopupSection::BranchInput;
                }
            }
            PopupSection::Worktrees => {
                let current = self.popup_state.worktree_list.selected().unwrap_or(0);
                if current + 1 < self.worktrees.len() {
                    self.popup_state.worktree_list.select(Some(current + 1));
                } else if !self.issues.is_empty() {
                    self.popup_state.section = PopupSection::Issues;
                    self.popup_state.issue_list.select(Some(0));
                } else {
                    self.popup_state.section = PopupSection::BranchInput;
                }
            }
            PopupSection::Issues => {
                let current = self.popup_state.issue_list.selected().unwrap_or(0);
                if current + 1 < self.issues.len() {
                    self.popup_state.issue_list.select(Some(current + 1));
                } else {
                    self.popup_state.section = PopupSection::BranchInput;
                }
            }
        }
    }

    /// Cross-section navigation: previous item
    ///
    /// Cycle: `BranchInput` → `Issues[k-1..0]` → `Worktrees[m-1..0]` → `Sessions[n-1..0]` → `BranchInput`
    pub(super) fn cross_section_prev(&mut self) {
        match self.popup_state.section {
            PopupSection::BranchInput => {
                // BranchInput → Issues[last] (or previous non-empty section)
                if !self.issues.is_empty() {
                    self.popup_state.section = PopupSection::Issues;
                    self.popup_state
                        .issue_list
                        .select(Some(self.issues.len() - 1));
                } else if !self.worktrees.is_empty() {
                    self.popup_state.section = PopupSection::Worktrees;
                    self.popup_state
                        .worktree_list
                        .select(Some(self.worktrees.len() - 1));
                } else if !self.sessions.is_empty() {
                    self.popup_state.section = PopupSection::Sessions;
                    self.popup_state
                        .session_list
                        .select(Some(self.sessions.len() - 1));
                }
            }
            PopupSection::Sessions => {
                let current = self.popup_state.session_list.selected().unwrap_or(0);
                if current > 0 {
                    self.popup_state.session_list.select(Some(current - 1));
                } else {
                    self.popup_state.section = PopupSection::BranchInput;
                }
            }
            PopupSection::Worktrees => {
                let current = self.popup_state.worktree_list.selected().unwrap_or(0);
                if current > 0 {
                    self.popup_state.worktree_list.select(Some(current - 1));
                } else if !self.sessions.is_empty() {
                    self.popup_state.section = PopupSection::Sessions;
                    self.popup_state
                        .session_list
                        .select(Some(self.sessions.len() - 1));
                } else {
                    self.popup_state.section = PopupSection::BranchInput;
                }
            }
            PopupSection::Issues => {
                let current = self.popup_state.issue_list.selected().unwrap_or(0);
                if current > 0 {
                    self.popup_state.issue_list.select(Some(current - 1));
                } else if !self.worktrees.is_empty() {
                    self.popup_state.section = PopupSection::Worktrees;
                    self.popup_state
                        .worktree_list
                        .select(Some(self.worktrees.len() - 1));
                } else if !self.sessions.is_empty() {
                    self.popup_state.section = PopupSection::Sessions;
                    self.popup_state
                        .session_list
                        .select(Some(self.sessions.len() - 1));
                } else {
                    self.popup_state.section = PopupSection::BranchInput;
                }
            }
        }
    }
}
