//! Input handling for the Settings dialog.
//!
//! Implements the InputHandler trait for SettingsState, routing input
//! through the focus hierarchy: Dialog -> Panel -> Control.

use super::items::SettingControl;
use super::state::{FocusPanel, SettingsState};
use crate::input::handler::{DeferredAction, InputContext, InputHandler, InputResult};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

/// Button action in entry dialog
enum ButtonAction {
    Save,
    Delete,
    Cancel,
}

/// Control activation action in entry dialog
enum ControlAction {
    ToggleBool,
    ToggleDropdown,
    StartEditing,
    OpenNestedDialog,
}

impl InputHandler for SettingsState {
    fn handle_key_event(&mut self, event: &KeyEvent, ctx: &mut InputContext) -> InputResult {
        // Entry dialog takes priority when open
        if self.has_entry_dialog() {
            return self.handle_entry_dialog_input(event, ctx);
        }

        // Confirmation dialog takes priority
        if self.showing_confirm_dialog {
            return self.handle_confirm_dialog_input(event, ctx);
        }

        // Reset confirmation dialog takes priority
        if self.showing_reset_dialog {
            return self.handle_reset_dialog_input(event);
        }

        // Help overlay takes priority
        if self.showing_help {
            return self.handle_help_input(event, ctx);
        }

        // Search mode takes priority
        if self.search_active {
            return self.handle_search_input(event, ctx);
        }

        // Global shortcut: Ctrl+S to save
        if event.modifiers.contains(KeyModifiers::CONTROL)
            && matches!(event.code, KeyCode::Char('s') | KeyCode::Char('S'))
        {
            ctx.defer(DeferredAction::CloseSettings { save: true });
            return InputResult::Consumed;
        }

        // Route to focused panel
        match self.focus_panel() {
            FocusPanel::Categories => self.handle_categories_input(event, ctx),
            FocusPanel::Settings => self.handle_settings_input(event, ctx),
            FocusPanel::Footer => self.handle_footer_input(event, ctx),
        }
    }

    fn is_modal(&self) -> bool {
        true // Settings dialog consumes all unhandled input
    }
}

impl SettingsState {
    /// Handle input when entry dialog is open
    ///
    /// Uses the same input flow as the main settings UI:
    /// 1. If in text editing mode -> handle text input
    /// 2. If dropdown is open -> handle dropdown navigation
    /// 3. Otherwise -> handle navigation and control activation
    fn handle_entry_dialog_input(
        &mut self,
        event: &KeyEvent,
        ctx: &mut InputContext,
    ) -> InputResult {
        // Ctrl+S saves entry dialog from any mode
        if event.modifiers.contains(KeyModifiers::CONTROL)
            && matches!(event.code, KeyCode::Char('s') | KeyCode::Char('S'))
        {
            self.save_entry_dialog();
            return InputResult::Consumed;
        }

        // Check if we're in a special editing mode
        let (editing_text, dropdown_open) = if let Some(dialog) = self.entry_dialog() {
            let dropdown_open = dialog
                .current_item()
                .map(|item| matches!(&item.control, SettingControl::Dropdown(s) if s.open))
                .unwrap_or(false);
            (dialog.editing_text, dropdown_open)
        } else {
            return InputResult::Consumed;
        };

        // Route to appropriate handler based on mode
        if editing_text {
            self.handle_entry_dialog_text_editing(event, ctx)
        } else if dropdown_open {
            self.handle_entry_dialog_dropdown(event)
        } else {
            self.handle_entry_dialog_navigation(event, ctx)
        }
    }

    /// Handle text editing input in entry dialog (same pattern as handle_text_editing_input)
    fn handle_entry_dialog_text_editing(
        &mut self,
        event: &KeyEvent,
        ctx: &mut InputContext,
    ) -> InputResult {
        // Check if we're editing JSON
        let is_editing_json = self
            .entry_dialog()
            .map(|d| d.is_editing_json())
            .unwrap_or(false);

        // Check validation first before borrowing dialog mutably
        let can_exit = self.entry_dialog_can_exit_text_editing();

        let Some(dialog) = self.entry_dialog_mut() else {
            return InputResult::Consumed;
        };

        match event.code {
            KeyCode::Esc => {
                // Escape accepts changes (same as Tab) - exit editing mode
                if !can_exit {
                    // If validation fails, just stop editing anyway (accept whatever is there)
                }
                dialog.stop_editing();
            }
            KeyCode::Enter => {
                if is_editing_json {
                    // Insert newline in JSON editor
                    dialog.insert_newline();
                } else {
                    // Add item for TextList, or stop editing
                    if let Some(item) = dialog.current_item_mut() {
                        if let SettingControl::TextList(state) = &mut item.control {
                            state.add_item();
                        }
                    }
                }
            }
            KeyCode::Char(c) => {
                if event.modifiers.contains(KeyModifiers::CONTROL) {
                    match c {
                        'a' | 'A' => {
                            // Select all
                            dialog.select_all();
                        }
                        'c' | 'C' => {
                            // Copy selected text to clipboard
                            if let Some(text) = dialog.selected_text() {
                                ctx.defer(DeferredAction::CopyToClipboard(text));
                            }
                        }
                        'v' | 'V' => {
                            // Paste
                            ctx.defer(DeferredAction::PasteToSettings);
                        }
                        _ => {}
                    }
                } else {
                    dialog.insert_char(c);
                }
            }
            KeyCode::Backspace => {
                dialog.backspace();
            }
            KeyCode::Delete => {
                if is_editing_json {
                    // Delete character at cursor in JSON editor
                    dialog.delete();
                } else {
                    // Delete item in TextList
                    dialog.delete_list_item();
                }
            }
            KeyCode::Home => {
                dialog.cursor_home();
            }
            KeyCode::End => {
                dialog.cursor_end();
            }
            KeyCode::Left => {
                if is_editing_json && event.modifiers.contains(KeyModifiers::SHIFT) {
                    dialog.cursor_left_selecting();
                } else {
                    dialog.cursor_left();
                }
            }
            KeyCode::Right => {
                if is_editing_json && event.modifiers.contains(KeyModifiers::SHIFT) {
                    dialog.cursor_right_selecting();
                } else {
                    dialog.cursor_right();
                }
            }
            KeyCode::Up => {
                if is_editing_json {
                    // Move cursor up in JSON editor
                    if event.modifiers.contains(KeyModifiers::SHIFT) {
                        dialog.cursor_up_selecting();
                    } else {
                        dialog.cursor_up();
                    }
                } else {
                    // Auto-accept pending text in TextList before navigating
                    if let Some(item) = dialog.current_item_mut() {
                        if let SettingControl::TextList(state) = &mut item.control {
                            state.add_item();
                            state.focus_prev();
                        }
                    }
                }
            }
            KeyCode::Down => {
                if is_editing_json {
                    // Move cursor down in JSON editor
                    if event.modifiers.contains(KeyModifiers::SHIFT) {
                        dialog.cursor_down_selecting();
                    } else {
                        dialog.cursor_down();
                    }
                } else {
                    // Auto-accept pending text in TextList before navigating
                    if let Some(item) = dialog.current_item_mut() {
                        if let SettingControl::TextList(state) = &mut item.control {
                            state.add_item();
                            state.focus_next();
                        }
                    }
                }
            }
            KeyCode::Tab => {
                if is_editing_json {
                    // Tab exits JSON editor if JSON is valid, otherwise ignored
                    let is_valid = dialog
                        .current_item()
                        .map(|item| {
                            if let SettingControl::Json(state) = &item.control {
                                state.is_valid()
                            } else {
                                true
                            }
                        })
                        .unwrap_or(true);

                    if is_valid {
                        // Commit changes and stop editing
                        if let Some(item) = dialog.current_item_mut() {
                            if let SettingControl::Json(state) = &mut item.control {
                                state.commit();
                            }
                        }
                        dialog.stop_editing();
                    }
                    // If not valid, Tab is ignored (user must fix or press Esc)
                } else {
                    // Auto-accept pending text in TextList before exiting
                    if let Some(item) = dialog.current_item_mut() {
                        if let SettingControl::TextList(state) = &mut item.control {
                            state.add_item();
                        }
                    }
                    // Tab exits text editing mode for non-JSON controls (TextList, Text)
                    dialog.stop_editing();
                }
            }
            _ => {}
        }
        InputResult::Consumed
    }

    /// Handle dropdown navigation in entry dialog (same pattern as handle_dropdown_input)
    fn handle_entry_dialog_dropdown(&mut self, event: &KeyEvent) -> InputResult {
        let Some(dialog) = self.entry_dialog_mut() else {
            return InputResult::Consumed;
        };

        match event.code {
            KeyCode::Up => {
                dialog.dropdown_prev();
            }
            KeyCode::Down => {
                dialog.dropdown_next();
            }
            KeyCode::Enter => {
                dialog.dropdown_confirm();
            }
            KeyCode::Esc => {
                dialog.dropdown_confirm(); // Close dropdown
            }
            _ => {}
        }
        InputResult::Consumed
    }

    /// Handle navigation and activation in entry dialog (same pattern as handle_settings_input)
    fn handle_entry_dialog_navigation(
        &mut self,
        event: &KeyEvent,
        ctx: &mut InputContext,
    ) -> InputResult {
        match event.code {
            KeyCode::Esc => {
                self.close_entry_dialog();
            }
            KeyCode::Up => {
                if let Some(dialog) = self.entry_dialog_mut() {
                    dialog.focus_prev();
                }
            }
            KeyCode::Down => {
                if let Some(dialog) = self.entry_dialog_mut() {
                    dialog.focus_next();
                }
            }
            KeyCode::Tab => {
                // Tab cycles sequentially through all fields, sub-fields, and buttons
                if let Some(dialog) = self.entry_dialog_mut() {
                    dialog.focus_next();
                }
            }
            KeyCode::BackTab => {
                // Shift+Tab cycles in reverse
                if let Some(dialog) = self.entry_dialog_mut() {
                    dialog.focus_prev();
                }
            }
            KeyCode::Left => {
                if let Some(dialog) = self.entry_dialog_mut() {
                    if !dialog.focus_on_buttons {
                        dialog.decrement_number();
                    } else if dialog.focused_button > 0 {
                        dialog.focused_button -= 1;
                    }
                }
            }
            KeyCode::Right => {
                if let Some(dialog) = self.entry_dialog_mut() {
                    if !dialog.focus_on_buttons {
                        dialog.increment_number();
                    } else if dialog.focused_button + 1 < dialog.button_count() {
                        dialog.focused_button += 1;
                    }
                }
            }
            KeyCode::Enter => {
                // Check button state first with immutable borrow
                let button_action = self.entry_dialog().and_then(|dialog| {
                    if dialog.focus_on_buttons {
                        let cancel_idx = dialog.button_count() - 1;
                        if dialog.focused_button == 0 {
                            Some(ButtonAction::Save)
                        } else if !dialog.is_new && !dialog.no_delete && dialog.focused_button == 1
                        {
                            Some(ButtonAction::Delete)
                        } else if dialog.focused_button == cancel_idx {
                            Some(ButtonAction::Cancel)
                        } else {
                            None
                        }
                    } else {
                        None
                    }
                });

                if let Some(action) = button_action {
                    match action {
                        ButtonAction::Save => self.save_entry_dialog(),
                        ButtonAction::Delete => self.delete_entry_dialog(),
                        ButtonAction::Cancel => self.close_entry_dialog(),
                    }
                } else if event.modifiers.contains(KeyModifiers::CONTROL) {
                    // Ctrl+Enter always saves
                    self.save_entry_dialog();
                } else {
                    // Activate current control
                    let control_action = self
                        .entry_dialog()
                        .and_then(|dialog| {
                            dialog.current_item().map(|item| match &item.control {
                                SettingControl::Toggle(_) => Some(ControlAction::ToggleBool),
                                SettingControl::Dropdown(_) => Some(ControlAction::ToggleDropdown),
                                SettingControl::Text(_)
                                | SettingControl::TextList(_)
                                | SettingControl::DualList(_)
                                | SettingControl::Number(_)
                                | SettingControl::Json(_) => Some(ControlAction::StartEditing),
                                SettingControl::Map(_) | SettingControl::ObjectArray(_) => {
                                    Some(ControlAction::OpenNestedDialog)
                                }
                                _ => None,
                            })
                        })
                        .flatten();

                    if let Some(action) = control_action {
                        match action {
                            ControlAction::ToggleBool => {
                                if let Some(dialog) = self.entry_dialog_mut() {
                                    dialog.toggle_bool();
                                }
                            }
                            ControlAction::ToggleDropdown => {
                                if let Some(dialog) = self.entry_dialog_mut() {
                                    dialog.toggle_dropdown();
                                }
                            }
                            ControlAction::StartEditing => {
                                if let Some(dialog) = self.entry_dialog_mut() {
                                    dialog.start_editing();
                                }
                            }
                            ControlAction::OpenNestedDialog => {
                                self.open_nested_entry_dialog();
                            }
                        }
                    }
                }
            }
            KeyCode::Char(' ') => {
                // Space toggles booleans, activates dropdowns (but doesn't submit form)
                let control_action = self.entry_dialog().and_then(|dialog| {
                    if dialog.focus_on_buttons {
                        return None; // Space on buttons does nothing (Enter activates)
                    }
                    dialog.current_item().and_then(|item| match &item.control {
                        SettingControl::Toggle(_) => Some(ControlAction::ToggleBool),
                        SettingControl::Dropdown(_) => Some(ControlAction::ToggleDropdown),
                        _ => None,
                    })
                });

                if let Some(action) = control_action {
                    match action {
                        ControlAction::ToggleBool => {
                            if let Some(dialog) = self.entry_dialog_mut() {
                                dialog.toggle_bool();
                            }
                        }
                        ControlAction::ToggleDropdown => {
                            if let Some(dialog) = self.entry_dialog_mut() {
                                dialog.toggle_dropdown();
                            }
                        }
                        _ => {}
                    }
                }
            }
            KeyCode::Char(c) => {
                // Auto-enter edit mode when typing on a text or number field
                let can_auto_edit = self
                    .entry_dialog()
                    .and_then(|dialog| {
                        if dialog.focus_on_buttons {
                            return None;
                        }
                        dialog.current_item().map(|item| match &item.control {
                            SettingControl::Text(_) | SettingControl::TextList(_) => true,
                            SettingControl::Number(_) => c.is_ascii_digit() || c == '-' || c == '.',
                            _ => false,
                        })
                    })
                    .unwrap_or(false);

                if can_auto_edit {
                    if let Some(dialog) = self.entry_dialog_mut() {
                        dialog.start_editing();
                    }
                    // Now forward the character to the text editing handler
                    return self.handle_entry_dialog_text_editing(
                        &KeyEvent::new(KeyCode::Char(c), event.modifiers),
                        ctx,
                    );
                }
            }
            _ => {}
        }
        InputResult::Consumed
    }

    /// Handle input when confirmation dialog is showing
    fn handle_confirm_dialog_input(
        &mut self,
        event: &KeyEvent,
        ctx: &mut InputContext,
    ) -> InputResult {
        match event.code {
            KeyCode::Left | KeyCode::BackTab => {
                if self.confirm_dialog_selection > 0 {
                    self.confirm_dialog_selection -= 1;
                }
                InputResult::Consumed
            }
            KeyCode::Right | KeyCode::Tab => {
                if self.confirm_dialog_selection < 2 {
                    self.confirm_dialog_selection += 1;
                }
                InputResult::Consumed
            }
            KeyCode::Enter => {
                match self.confirm_dialog_selection {
                    0 => ctx.defer(DeferredAction::CloseSettings { save: true }), // Save
                    1 => ctx.defer(DeferredAction::CloseSettings { save: false }), // Discard
                    2 => self.showing_confirm_dialog = false, // Cancel - back to settings
                    _ => {}
                }
                InputResult::Consumed
            }
            KeyCode::Esc => {
                self.showing_confirm_dialog = false;
                InputResult::Consumed
            }
            KeyCode::Char('s') | KeyCode::Char('S') => {
                ctx.defer(DeferredAction::CloseSettings { save: true });
                InputResult::Consumed
            }
            KeyCode::Char('d') | KeyCode::Char('D') => {
                ctx.defer(DeferredAction::CloseSettings { save: false });
                InputResult::Consumed
            }
            _ => InputResult::Consumed, // Modal: consume all
        }
    }

    /// Handle input when reset confirmation dialog is showing
    fn handle_reset_dialog_input(&mut self, event: &KeyEvent) -> InputResult {
        match event.code {
            KeyCode::Left | KeyCode::BackTab => {
                if self.reset_dialog_selection > 0 {
                    self.reset_dialog_selection -= 1;
                }
                InputResult::Consumed
            }
            KeyCode::Right | KeyCode::Tab => {
                if self.reset_dialog_selection < 1 {
                    self.reset_dialog_selection += 1;
                }
                InputResult::Consumed
            }
            KeyCode::Enter => {
                match self.reset_dialog_selection {
                    0 => {
                        // Reset all changes
                        self.discard_changes();
                        self.showing_reset_dialog = false;
                    }
                    1 => {
                        // Cancel - back to settings
                        self.showing_reset_dialog = false;
                    }
                    _ => {}
                }
                InputResult::Consumed
            }
            KeyCode::Esc => {
                self.showing_reset_dialog = false;
                InputResult::Consumed
            }
            KeyCode::Char('r') | KeyCode::Char('R') => {
                self.discard_changes();
                self.showing_reset_dialog = false;
                InputResult::Consumed
            }
            _ => InputResult::Consumed, // Modal: consume all
        }
    }

    /// Handle input when help overlay is showing
    fn handle_help_input(&mut self, _event: &KeyEvent, _ctx: &mut InputContext) -> InputResult {
        // Any key dismisses help
        self.showing_help = false;
        InputResult::Consumed
    }

    /// Handle input when search is active
    fn handle_search_input(&mut self, event: &KeyEvent, _ctx: &mut InputContext) -> InputResult {
        match event.code {
            KeyCode::Esc => {
                self.cancel_search();
                InputResult::Consumed
            }
            KeyCode::Enter => {
                self.jump_to_search_result();
                InputResult::Consumed
            }
            KeyCode::Up => {
                self.search_prev();
                InputResult::Consumed
            }
            KeyCode::Down => {
                self.search_next();
                InputResult::Consumed
            }
            KeyCode::Char(c) => {
                self.search_push_char(c);
                InputResult::Consumed
            }
            KeyCode::Backspace => {
                self.search_pop_char();
                InputResult::Consumed
            }
            _ => InputResult::Consumed, // Modal: consume all
        }
    }

    /// Handle input when Categories panel is focused
    fn handle_categories_input(&mut self, event: &KeyEvent, ctx: &mut InputContext) -> InputResult {
        match event.code {
            KeyCode::Up => {
                self.select_prev();
                InputResult::Consumed
            }
            KeyCode::Down => {
                self.select_next();
                InputResult::Consumed
            }
            KeyCode::Tab => {
                self.toggle_focus();
                InputResult::Consumed
            }
            KeyCode::BackTab => {
                self.toggle_focus_backward();
                InputResult::Consumed
            }
            KeyCode::Char('/') => {
                self.start_search();
                InputResult::Consumed
            }
            KeyCode::Char('?') => {
                self.toggle_help();
                InputResult::Consumed
            }
            KeyCode::Esc => {
                self.request_close(ctx);
                InputResult::Consumed
            }
            KeyCode::Enter | KeyCode::Right => {
                // Enter/Right on categories: move focus to settings panel
                self.focus.set(FocusPanel::Settings);
                InputResult::Consumed
            }
            _ => InputResult::Ignored, // Let modal catch it
        }
    }

    /// Handle input when Settings panel is focused
    fn handle_settings_input(&mut self, event: &KeyEvent, ctx: &mut InputContext) -> InputResult {
        // If editing text, handle text input
        if self.editing_text {
            return self.handle_text_editing_input(event, ctx);
        }

        // If editing number input, handle number input
        if self.is_number_editing() {
            return self.handle_number_editing_input(event, ctx);
        }

        // If dropdown is open, handle dropdown navigation
        if self.is_dropdown_open() {
            return self.handle_dropdown_input(event, ctx);
        }

        match event.code {
            KeyCode::Up => {
                self.select_prev();
                InputResult::Consumed
            }
            KeyCode::Down => {
                self.select_next();
                InputResult::Consumed
            }
            KeyCode::Tab => {
                self.toggle_focus();
                InputResult::Consumed
            }
            KeyCode::BackTab => {
                self.toggle_focus_backward();
                InputResult::Consumed
            }
            KeyCode::Left => {
                // Left on number controls: decrement value
                // Left on other controls: navigate back to categories
                if self.is_number_control() {
                    self.handle_control_decrement();
                } else {
                    self.update_control_focus(false);
                    self.focus.set(FocusPanel::Categories);
                }
                InputResult::Consumed
            }
            KeyCode::Right => {
                self.handle_control_increment();
                InputResult::Consumed
            }
            KeyCode::Enter | KeyCode::Char(' ') => {
                self.handle_control_activate(ctx);
                InputResult::Consumed
            }
            KeyCode::PageDown => {
                self.select_next_page();
                InputResult::Consumed
            }
            KeyCode::PageUp => {
                self.select_prev_page();
                InputResult::Consumed
            }
            KeyCode::Char('/') => {
                self.start_search();
                InputResult::Consumed
            }
            KeyCode::Char('?') => {
                self.toggle_help();
                InputResult::Consumed
            }
            KeyCode::Delete => {
                // Delete key: set nullable setting to null (inherit)
                self.set_current_to_null();
                InputResult::Consumed
            }
            KeyCode::Esc => {
                self.request_close(ctx);
                InputResult::Consumed
            }
            _ => InputResult::Ignored, // Let modal catch it
        }
    }

    /// Handle input when Footer is focused
    /// Footer buttons: [Layer] [Reset] [Save] [Cancel] + [Edit] on left for advanced users
    /// Tab cycles between buttons; after last button, moves to Categories panel
    fn handle_footer_input(&mut self, event: &KeyEvent, ctx: &mut InputContext) -> InputResult {
        const FOOTER_BUTTON_COUNT: usize = 5;

        match event.code {
            KeyCode::Left | KeyCode::BackTab => {
                // Move to previous button, or wrap to Categories panel
                if self.footer_button_index > 0 {
                    self.footer_button_index -= 1;
                } else {
                    self.focus.set(FocusPanel::Settings);
                }
                InputResult::Consumed
            }
            KeyCode::Right => {
                // Move to next button
                if self.footer_button_index < FOOTER_BUTTON_COUNT - 1 {
                    self.footer_button_index += 1;
                }
                InputResult::Consumed
            }
            KeyCode::Tab => {
                // Move to next button, or wrap to Categories panel
                if self.footer_button_index < FOOTER_BUTTON_COUNT - 1 {
                    self.footer_button_index += 1;
                } else {
                    self.focus.set(FocusPanel::Categories);
                }
                InputResult::Consumed
            }
            KeyCode::Enter => {
                match self.footer_button_index {
                    0 => self.cycle_target_layer(), // Layer button
                    1 => {
                        // Reset/Inherit button — for nullable items, set to null (inherit);
                        // otherwise show reset-all dialog
                        let is_nullable_set = self
                            .current_item()
                            .map(|item| item.nullable && !item.is_null)
                            .unwrap_or(false);
                        if is_nullable_set {
                            self.set_current_to_null();
                        } else {
                            self.request_reset();
                        }
                    }
                    2 => ctx.defer(DeferredAction::CloseSettings { save: true }),
                    3 => self.request_close(ctx),
                    4 => ctx.defer(DeferredAction::OpenConfigFile {
                        layer: self.target_layer,
                    }), // Edit config file
                    _ => {}
                }
                InputResult::Consumed
            }
            KeyCode::Esc => {
                self.request_close(ctx);
                InputResult::Consumed
            }
            KeyCode::Char('/') => {
                self.start_search();
                InputResult::Consumed
            }
            KeyCode::Char('?') => {
                self.toggle_help();
                InputResult::Consumed
            }
            _ => InputResult::Ignored, // Let modal catch it
        }
    }

    /// Handle input when editing text in a control
    fn handle_text_editing_input(
        &mut self,
        event: &KeyEvent,
        ctx: &mut InputContext,
    ) -> InputResult {
        let is_json = self.is_editing_json();

        if is_json {
            return self.handle_json_editing_input(event, ctx);
        }

        // DualList has its own keyboard handling (no text input)
        if self.is_editing_dual_list() {
            return self.handle_dual_list_editing_input(event);
        }

        match event.code {
            KeyCode::Esc => {
                // Check if current text field requires JSON validation
                if !self.can_exit_text_editing() {
                    return InputResult::Consumed;
                }
                self.stop_editing();
                InputResult::Consumed
            }
            KeyCode::Enter => {
                self.text_add_item();
                InputResult::Consumed
            }
            KeyCode::Char(c) => {
                self.text_insert(c);
                InputResult::Consumed
            }
            KeyCode::Backspace => {
                self.text_backspace();
                InputResult::Consumed
            }
            KeyCode::Delete => {
                self.text_remove_focused();
                InputResult::Consumed
            }
            KeyCode::Left => {
                self.text_move_left();
                InputResult::Consumed
            }
            KeyCode::Right => {
                self.text_move_right();
                InputResult::Consumed
            }
            KeyCode::Up => {
                self.text_focus_prev();
                InputResult::Consumed
            }
            KeyCode::Down => {
                self.text_focus_next();
                InputResult::Consumed
            }
            KeyCode::Tab => {
                // Tab exits text editing mode and advances focus to the next panel
                self.stop_editing();
                self.toggle_focus();
                InputResult::Consumed
            }
            _ => InputResult::Consumed, // Consume all during text edit
        }
    }

    /// Handle input when editing a DualList control
    fn handle_dual_list_editing_input(&mut self, event: &KeyEvent) -> InputResult {
        use crate::view::controls::DualListColumn;
        let shift = event.modifiers.contains(KeyModifiers::SHIFT);
        match event.code {
            KeyCode::Esc => {
                self.stop_editing();
            }
            // Tab/BackTab propagate to the settings panel (exit editing)
            KeyCode::Tab | KeyCode::BackTab => {
                self.stop_editing();
                // Return Ignored so the settings panel handles Tab/BackTab
                return InputResult::Ignored;
            }
            KeyCode::Up if shift => {
                self.with_current_dual_list_mut(|dl| dl.move_up());
                self.on_value_changed();
            }
            KeyCode::Down if shift => {
                self.with_current_dual_list_mut(|dl| dl.move_down());
                self.on_value_changed();
            }
            KeyCode::Up => {
                self.with_current_dual_list_mut(|dl| dl.cursor_up());
            }
            KeyCode::Down => {
                self.with_current_dual_list_mut(|dl| dl.cursor_down());
            }
            KeyCode::Right if shift => {
                // Shift+Right: add selected available item to included, follow it
                let changed = self
                    .with_current_dual_list_mut(|dl| {
                        if dl.active_column == DualListColumn::Available {
                            dl.add_selected();
                            // Move focus to the Included column, cursor on the newly added item (last)
                            dl.active_column = DualListColumn::Included;
                            dl.included_cursor = dl.included.len().saturating_sub(1);
                            true
                        } else {
                            false
                        }
                    })
                    .unwrap_or(false);
                if changed {
                    self.on_value_changed();
                    self.refresh_dual_list_sibling();
                }
            }
            KeyCode::Left if shift => {
                // Shift+Left: remove selected included item back to available, follow it
                let changed = self
                    .with_current_dual_list_mut(|dl| {
                        if dl.active_column == DualListColumn::Included {
                            let value = dl.included.get(dl.included_cursor).cloned();
                            dl.remove_selected();
                            // Move focus to Available column, find the removed item
                            dl.active_column = DualListColumn::Available;
                            if let Some(val) = value {
                                let avail = dl.available_items();
                                if let Some(pos) = avail.iter().position(|(v, _)| *v == val) {
                                    dl.available_cursor = pos;
                                }
                            }
                            true
                        } else {
                            false
                        }
                    })
                    .unwrap_or(false);
                if changed {
                    self.on_value_changed();
                    self.refresh_dual_list_sibling();
                }
            }
            KeyCode::Right => {
                // Plain Right: switch to Included column
                self.with_current_dual_list_mut(|dl| {
                    dl.active_column = DualListColumn::Included;
                });
            }
            KeyCode::Left => {
                // Plain Left: switch to Available column
                self.with_current_dual_list_mut(|dl| {
                    dl.active_column = DualListColumn::Available;
                });
            }
            KeyCode::Enter => {
                // Enter adds/removes based on active column
                let changed = self
                    .with_current_dual_list_mut(|dl| match dl.active_column {
                        DualListColumn::Available => dl.add_selected(),
                        DualListColumn::Included => dl.remove_selected(),
                    })
                    .is_some();
                if changed {
                    self.on_value_changed();
                    self.refresh_dual_list_sibling();
                }
            }
            _ => {}
        }
        InputResult::Consumed
    }

    /// Handle input when editing a JSON control (multiline editor)
    fn handle_json_editing_input(
        &mut self,
        event: &KeyEvent,
        ctx: &mut InputContext,
    ) -> InputResult {
        match event.code {
            KeyCode::Esc | KeyCode::Tab => {
                // Accept if valid JSON, revert if invalid, then stop editing
                self.json_exit_editing();
            }
            KeyCode::Enter => {
                self.json_insert_newline();
            }
            KeyCode::Char(c) => {
                if event.modifiers.contains(KeyModifiers::CONTROL) {
                    match c {
                        'a' | 'A' => self.json_select_all(),
                        'c' | 'C' => {
                            if let Some(text) = self.json_selected_text() {
                                ctx.defer(DeferredAction::CopyToClipboard(text));
                            }
                        }
                        'v' | 'V' => {
                            ctx.defer(DeferredAction::PasteToSettings);
                        }
                        _ => {}
                    }
                } else {
                    self.text_insert(c);
                }
            }
            KeyCode::Backspace => {
                self.text_backspace();
            }
            KeyCode::Delete => {
                self.json_delete();
            }
            KeyCode::Left => {
                if event.modifiers.contains(KeyModifiers::SHIFT) {
                    self.json_cursor_left_selecting();
                } else {
                    self.text_move_left();
                }
            }
            KeyCode::Right => {
                if event.modifiers.contains(KeyModifiers::SHIFT) {
                    self.json_cursor_right_selecting();
                } else {
                    self.text_move_right();
                }
            }
            KeyCode::Up => {
                if event.modifiers.contains(KeyModifiers::SHIFT) {
                    self.json_cursor_up_selecting();
                } else {
                    self.json_cursor_up();
                }
            }
            KeyCode::Down => {
                if event.modifiers.contains(KeyModifiers::SHIFT) {
                    self.json_cursor_down_selecting();
                } else {
                    self.json_cursor_down();
                }
            }
            _ => {}
        }
        InputResult::Consumed
    }

    /// Handle input when editing a number input control
    fn handle_number_editing_input(
        &mut self,
        event: &KeyEvent,
        _ctx: &mut InputContext,
    ) -> InputResult {
        let ctrl = event.modifiers.contains(KeyModifiers::CONTROL);
        let shift = event.modifiers.contains(KeyModifiers::SHIFT);

        match event.code {
            KeyCode::Esc => {
                self.number_cancel();
            }
            KeyCode::Enter => {
                self.number_confirm();
            }
            KeyCode::Char('a') if ctrl => {
                self.number_select_all();
            }
            KeyCode::Char(c) => {
                self.number_insert(c);
            }
            KeyCode::Backspace if ctrl => {
                self.number_delete_word_backward();
            }
            KeyCode::Backspace => {
                self.number_backspace();
            }
            KeyCode::Delete if ctrl => {
                self.number_delete_word_forward();
            }
            KeyCode::Delete => {
                self.number_delete();
            }
            KeyCode::Left if ctrl && shift => {
                self.number_move_word_left_selecting();
            }
            KeyCode::Left if ctrl => {
                self.number_move_word_left();
            }
            KeyCode::Left if shift => {
                self.number_move_left_selecting();
            }
            KeyCode::Left => {
                self.number_move_left();
            }
            KeyCode::Right if ctrl && shift => {
                self.number_move_word_right_selecting();
            }
            KeyCode::Right if ctrl => {
                self.number_move_word_right();
            }
            KeyCode::Right if shift => {
                self.number_move_right_selecting();
            }
            KeyCode::Right => {
                self.number_move_right();
            }
            KeyCode::Home if shift => {
                self.number_move_home_selecting();
            }
            KeyCode::Home => {
                self.number_move_home();
            }
            KeyCode::End if shift => {
                self.number_move_end_selecting();
            }
            KeyCode::End => {
                self.number_move_end();
            }
            _ => {}
        }
        InputResult::Consumed // Consume all during number edit
    }

    /// Handle input when dropdown is open
    fn handle_dropdown_input(&mut self, event: &KeyEvent, _ctx: &mut InputContext) -> InputResult {
        match event.code {
            KeyCode::Up => {
                self.dropdown_prev();
                InputResult::Consumed
            }
            KeyCode::Down => {
                self.dropdown_next();
                InputResult::Consumed
            }
            KeyCode::Home => {
                self.dropdown_home();
                InputResult::Consumed
            }
            KeyCode::End => {
                self.dropdown_end();
                InputResult::Consumed
            }
            KeyCode::Enter => {
                self.dropdown_confirm();
                InputResult::Consumed
            }
            KeyCode::Esc => {
                self.dropdown_cancel();
                InputResult::Consumed
            }
            _ => InputResult::Consumed, // Consume all while dropdown is open
        }
    }

    /// Request to reset all changes (shows confirm dialog if there are changes)
    fn request_reset(&mut self) {
        if self.has_changes() {
            self.showing_reset_dialog = true;
            self.reset_dialog_selection = 0;
        }
    }

    /// Request to close settings (shows confirm dialog if there are changes)
    fn request_close(&mut self, ctx: &mut InputContext) {
        if self.has_changes() {
            self.showing_confirm_dialog = true;
            self.confirm_dialog_selection = 0;
        } else {
            ctx.defer(DeferredAction::CloseSettings { save: false });
        }
    }

    /// Handle control activation (Enter/Space on a setting)
    fn handle_control_activate(&mut self, _ctx: &mut InputContext) {
        if let Some(item) = self.current_item_mut() {
            match &mut item.control {
                SettingControl::Toggle(ref mut state) => {
                    state.checked = !state.checked;
                    self.on_value_changed();
                }
                SettingControl::Dropdown(_) => {
                    self.dropdown_toggle();
                }
                SettingControl::Number(_) => {
                    self.start_number_editing();
                }
                SettingControl::Text(_) => {
                    self.start_editing();
                }
                SettingControl::TextList(_) | SettingControl::DualList(_) => {
                    self.start_editing();
                }
                SettingControl::Map(ref mut state) => {
                    if state.focused_entry.is_none() {
                        // On add-new row: open dialog with empty key
                        if state.value_schema.is_some() {
                            self.open_add_entry_dialog();
                        }
                    } else if state.value_schema.is_some() {
                        // Has schema: open entry dialog
                        self.open_entry_dialog();
                    } else {
                        // Toggle expanded
                        if let Some(idx) = state.focused_entry {
                            if state.expanded.contains(&idx) {
                                state.expanded.retain(|&i| i != idx);
                            } else {
                                state.expanded.push(idx);
                            }
                        }
                    }
                    self.on_value_changed();
                }
                SettingControl::Json(_) => {
                    self.start_editing();
                }
                SettingControl::ObjectArray(ref state) => {
                    if state.focused_index.is_none() {
                        // On add-new row: open dialog with empty item
                        if state.item_schema.is_some() {
                            self.open_add_array_item_dialog();
                        }
                    } else if state.item_schema.is_some() {
                        // Has schema: open edit dialog
                        self.open_edit_array_item_dialog();
                    }
                }
                SettingControl::Complex { .. } => {
                    // Not editable via simple controls
                }
            }
        }
    }

    /// Handle control increment (Right arrow on numbers/dropdowns)
    fn handle_control_increment(&mut self) {
        if let Some(item) = self.current_item_mut() {
            if let SettingControl::Number(ref mut state) = &mut item.control {
                state.value += 1;
                if let Some(max) = state.max {
                    state.value = state.value.min(max);
                }
                self.on_value_changed();
            }
        }
    }

    /// Handle control decrement (Left arrow on numbers)
    fn handle_control_decrement(&mut self) {
        if let Some(item) = self.current_item_mut() {
            if let SettingControl::Number(ref mut state) = &mut item.control {
                if state.value > 0 {
                    state.value -= 1;
                }
                if let Some(min) = state.min {
                    state.value = state.value.max(min);
                }
                self.on_value_changed();
            }
        }
    }
}

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

    fn key(code: KeyCode) -> KeyEvent {
        KeyEvent::new(code, KeyModifiers::NONE)
    }

    #[test]
    fn test_settings_is_modal() {
        // SettingsState should be modal - consume all unhandled input
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let state = SettingsState::new(schema, &config).unwrap();
        assert!(state.is_modal());
    }

    #[test]
    fn test_categories_panel_does_not_leak_to_settings() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;
        state.focus.set(FocusPanel::Categories);

        let mut ctx = InputContext::new();

        // Enter on categories should NOT affect settings items
        // It should just move focus to settings panel
        let result = state.handle_key_event(&key(KeyCode::Enter), &mut ctx);
        assert_eq!(result, InputResult::Consumed);
        assert_eq!(state.focus_panel(), FocusPanel::Settings);

        // Go back to categories
        state.focus.set(FocusPanel::Categories);

        // Left/Right on categories should be consumed but not affect settings
        let result = state.handle_key_event(&key(KeyCode::Right), &mut ctx);
        assert_eq!(result, InputResult::Consumed);
        // Should have moved to settings panel
        assert_eq!(state.focus_panel(), FocusPanel::Settings);
    }

    #[test]
    fn test_tab_cycles_focus_panels() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;

        let mut ctx = InputContext::new();

        // Start at Categories
        assert_eq!(state.focus_panel(), FocusPanel::Categories);

        // Tab -> Settings
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.focus_panel(), FocusPanel::Settings);

        // Tab -> Footer (defaults to Layer button, index 0)
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.focus_panel(), FocusPanel::Footer);
        assert_eq!(state.footer_button_index, 0);

        // Tab through footer buttons: 0 -> 1 -> 2 -> 3 -> 4 -> wrap to Categories
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.footer_button_index, 1);
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.footer_button_index, 2);
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.footer_button_index, 3);
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.footer_button_index, 4); // Edit button
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.focus_panel(), FocusPanel::Categories);

        // SECOND LOOP: Tab again should still land on Layer button when entering Footer
        // Tab -> Settings
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.focus_panel(), FocusPanel::Settings);

        // Tab -> Footer (should reset to Layer button, not stay on Edit)
        state.handle_key_event(&key(KeyCode::Tab), &mut ctx);
        assert_eq!(state.focus_panel(), FocusPanel::Footer);
        assert_eq!(
            state.footer_button_index, 0,
            "Footer should reset to Layer button (index 0) on second loop"
        );
    }

    #[test]
    fn test_escape_shows_confirm_dialog_with_changes() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;

        // Simulate a change
        state
            .pending_changes
            .insert("/test".to_string(), serde_json::json!(true));

        let mut ctx = InputContext::new();

        // Escape should show confirm dialog, not close directly
        state.handle_key_event(&key(KeyCode::Esc), &mut ctx);
        assert!(state.showing_confirm_dialog);
        assert!(ctx.deferred_actions.is_empty()); // No close action yet
    }

    #[test]
    fn test_escape_closes_directly_without_changes() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;

        let mut ctx = InputContext::new();

        // Escape without changes should defer close action
        state.handle_key_event(&key(KeyCode::Esc), &mut ctx);
        assert!(!state.showing_confirm_dialog);
        assert_eq!(ctx.deferred_actions.len(), 1);
        assert!(matches!(
            ctx.deferred_actions[0],
            DeferredAction::CloseSettings { save: false }
        ));
    }

    #[test]
    fn test_confirm_dialog_navigation() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;
        state.showing_confirm_dialog = true;
        state.confirm_dialog_selection = 0; // Save

        let mut ctx = InputContext::new();

        // Right -> Discard
        state.handle_key_event(&key(KeyCode::Right), &mut ctx);
        assert_eq!(state.confirm_dialog_selection, 1);

        // Right -> Cancel
        state.handle_key_event(&key(KeyCode::Right), &mut ctx);
        assert_eq!(state.confirm_dialog_selection, 2);

        // Right again -> stays at Cancel (no wrap)
        state.handle_key_event(&key(KeyCode::Right), &mut ctx);
        assert_eq!(state.confirm_dialog_selection, 2);

        // Left -> Discard
        state.handle_key_event(&key(KeyCode::Left), &mut ctx);
        assert_eq!(state.confirm_dialog_selection, 1);
    }

    #[test]
    fn test_search_mode_captures_typing() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;

        let mut ctx = InputContext::new();

        // Start search
        state.handle_key_event(&key(KeyCode::Char('/')), &mut ctx);
        assert!(state.search_active);

        // Type search query
        state.handle_key_event(&key(KeyCode::Char('t')), &mut ctx);
        state.handle_key_event(&key(KeyCode::Char('a')), &mut ctx);
        state.handle_key_event(&key(KeyCode::Char('b')), &mut ctx);
        assert_eq!(state.search_query, "tab");

        // Escape cancels search
        state.handle_key_event(&key(KeyCode::Esc), &mut ctx);
        assert!(!state.search_active);
        assert!(state.search_query.is_empty());
    }

    #[test]
    fn test_footer_button_activation() {
        let schema = include_str!("../../../plugins/config-schema.json");
        let config = crate::config::Config::default();
        let mut state = SettingsState::new(schema, &config).unwrap();
        state.visible = true;
        state.focus.set(FocusPanel::Footer);
        state.footer_button_index = 2; // Save button (0=Layer, 1=Reset, 2=Save, 3=Cancel)

        let mut ctx = InputContext::new();

        // Enter on Save button should defer save action
        state.handle_key_event(&key(KeyCode::Enter), &mut ctx);
        assert_eq!(ctx.deferred_actions.len(), 1);
        assert!(matches!(
            ctx.deferred_actions[0],
            DeferredAction::CloseSettings { save: true }
        ));
    }
}
