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

impl super::Santui {
    pub(super) fn handle_key(&mut self, key: KeyEvent) {
        // Ctrl+C quits immediately from any screen, even in raw mode where
        // it arrives as a key event rather than a signal.
        if matches!(key.code, KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL)) {
            self.app_state.running = false;
            return;
        }
        if self.palette_controller.is_open() {
            return self.handle_key_palette(key);
        }
        if self.app_state.theme_picker_open {
            return self.handle_key_theme_picker(key);
        }
        if self.app_state.show_about {
            return self.handle_key_about(key);
        }
        self.handle_key_normal(key);
    }

    fn handle_key_palette(&mut self, key: KeyEvent) {
        let cmds = self.plugin_manager.commands();
        let bi = &self.app_state.builtin_items;
        let action =
            self.palette_controller
                .handle_key(key, bi, self.plugin_manager.dynamic_items(), cmds);
        if let super::palette_controller::PaletteAction::Execute(idx) = action {
            self.execute_palette_selection(idx);
        }
    }

    fn execute_palette_selection(&mut self, idx: super::ItemIndex) {
        match idx {
            super::ItemIndex::Builtin(bi) => {
                let id = self.app_state.builtin_items[bi].0;
                match id {
                    super::BuiltinId::SignInGoogle => {
                        if let Some(ref auth) = self.auth {
                            if let Err(e) = auth.start_sign_in("google") {
                                log::error!("[auth] Google sign-in error: {e}");
                            }
                        }
                    }
                    super::BuiltinId::SignInGitHub => {
                        if let Some(ref auth) = self.auth {
                            if let Err(e) = auth.start_sign_in("github") {
                                log::error!("[auth] GitHub sign-in error: {e}");
                            }
                        }
                    }
                    super::BuiltinId::SignOut => {
                        if let Some(ref auth) = self.auth {
                            auth.sign_out();
                            self.plugin_manager.on_user_update_all(None);
                        }
                    }
                    super::BuiltinId::PluginRegistry => {
                        if let Some(idx) = self.plugin_manager.find_by_id("plugin-registry") {
                            self.plugin_manager.set_active(Some(idx));
                        }
                    }
                    super::BuiltinId::SwitchTheme => {
                        self.app_state.theme_picker_open = true;
                        let tm = &mut self.theme_manager;
                        let items: Vec<crate::widgets::filtered_list::DisplayItem> = tm
                            .themes
                            .iter()
                            .map(|(name, _)| crate::widgets::filtered_list::DisplayItem {
                                category: "",
                                label: name.as_str(),
                            })
                            .collect();
                        let mut filter = crate::widgets::filtered_list::FilteredListState::new();
                        filter.set_query(String::new(), &items);
                        filter.cursor = tm.current_idx;
                        tm.picker_filter = Some(filter);
                        tm.picker_orig_idx = tm.current_idx;
                    }
                    super::BuiltinId::About => {
                        self.app_state.show_about = true;
                    }
                    super::BuiltinId::Exit => {
                        self.app_state.running = false;
                    }
                }
            }
            super::ItemIndex::PluginCmd(pci) => {
                let (plugin_idx, local_idx, _) = self.plugin_manager.commands()[pci];
                if plugin_idx < self.plugin_manager.len() {
                    self.plugin_manager.set_active(Some(plugin_idx));
                    self.plugin_manager
                        .handle_palette_command(plugin_idx, local_idx);
                }
            }
            super::ItemIndex::Dynamic(di) => {
                if let Some((_cat, id, name)) = self.plugin_manager.dynamic_items().get(di).cloned()
                {
                    self.activate_plugin_by_id(&id, &name);
                }
            }
        }
    }

    pub(super) fn activate_plugin_by_id(&mut self, id: &str, name: &str) -> bool {
        if let Some(existing) = self.plugin_manager.find_by_id(id) {
            self.plugin_manager.set_active(Some(existing));
            return true;
        }

        let cfg_path = self.plugin_manager.data_dir().join("registry.toml");
        let Some(cfg) = crate::registry_config::RegistryConfig::load(&cfg_path) else {
            return false;
        };
        let Some(installed) = cfg.plugins.iter().find(|p| {
            p.path
                .file_stem()
                .and_then(|s| s.to_str())
                .map(|s| s.trim_end_matches(".exe"))
                .is_some_and(|stem| stem == id)
        }) else {
            return false;
        };

        let mut ctx = crate::plugin::PluginContext {
            theme: self.app_state.theme.clone(),
            auth: self.auth.clone(),
            data_dir: self.plugin_manager.data_dir().to_path_buf(),
        };

        match self.plugin_manager.spawn_and_init(
            id,
            name,
            &installed.path,
            &installed.capabilities,
            &mut ctx,
        ) {
            Ok(idx) => {
                self.plugin_manager.set_active(Some(idx));
                true
            }
            Err(_) => false,
        }
    }

    fn activate_carousel_item(&mut self, ci: usize) {
        let (id, name) = {
            let carousel = self.plugin_manager.carousel_items();
            let Some(item) = carousel.get(ci) else {
                return;
            };
            (item.id.clone(), item.name.clone())
        };
        self.activate_plugin_by_id(&id, &name);
    }

    fn handle_key_theme_picker(&mut self, key: KeyEvent) {
        use crate::widgets::filtered_list::DisplayItem;

        // Clone names to avoid borrow conflict with picker_filter.
        let theme_names: Vec<String> = self
            .theme_manager
            .themes
            .iter()
            .map(|(n, _)| n.clone())
            .collect();

        let filter = match self.theme_manager.picker_filter.as_mut() {
            Some(f) => f,
            None => return,
        };

        let items: Vec<DisplayItem> = theme_names
            .iter()
            .map(|name| DisplayItem {
                category: "",
                label: name.as_str(),
            })
            .collect();

        match key.code {
            KeyCode::Char(c)
                if c == 'p'
                    && key
                        .modifiers
                        .contains(crossterm::event::KeyModifiers::CONTROL) =>
            {
                self.select_theme(self.theme_manager.picker_orig_idx);
                self.app_state.theme_picker_open = false;
            }
            KeyCode::Char(_) if !key.modifiers.is_empty() => {}
            KeyCode::Char(c) => {
                filter.push_char(c, &items);
                if let Some(idx) = filter.selected_item() {
                    self.preview_theme(idx);
                }
            }
            KeyCode::Backspace => {
                filter.pop_char(&items);
                if let Some(idx) = filter.selected_item() {
                    self.preview_theme(idx);
                }
            }
            KeyCode::Up => {
                filter.move_up();
                if let Some(idx) = filter.selected_item() {
                    self.preview_theme(idx);
                }
            }
            KeyCode::Down => {
                filter.move_down();
                if let Some(idx) = filter.selected_item() {
                    self.preview_theme(idx);
                }
            }
            KeyCode::Enter => {
                if let Some(idx) = filter.selected_item() {
                    self.select_theme(idx);
                }
                self.app_state.theme_picker_open = false;
            }
            KeyCode::Esc => {
                self.select_theme(self.theme_manager.picker_orig_idx);
                self.app_state.theme_picker_open = false;
            }
            _ => {}
        }
    }

    fn handle_key_about(&mut self, key: KeyEvent) {
        if matches!(key.code, KeyCode::Esc) {
            self.app_state.show_about = false;
        }
    }

    fn handle_key_normal(&mut self, key: KeyEvent) {
        if key.code == self.bindings.open_palette.0
            && key.modifiers.contains(self.bindings.open_palette.1)
        {
            self.palette_controller.open();
            return;
        }

        match self.plugin_manager.active() {
            None => match key.code {
                _ if key.code == self.bindings.quit.0
                    && key.modifiers.contains(self.bindings.quit.1) =>
                {
                    self.app_state.running = false;
                }
                KeyCode::Char('r') => {
                    let mut ctx = crate::plugin::PluginContext {
                        theme: self.app_state.theme.clone(),
                        auth: self.auth.clone(),
                        data_dir: self.plugin_manager.data_dir().to_path_buf(),
                    };
                    self.plugin_manager.restart_crashed(&mut ctx);
                }
                _ if key.code == self.bindings.about.0
                    && key.modifiers.contains(self.bindings.about.1) =>
                {
                    self.app_state.show_about = true;
                }
                KeyCode::Right | KeyCode::Char('l') => {
                    let carousel = self.plugin_manager.carousel_items();
                    let n = carousel.len();
                    if n == 0 {
                        return;
                    }
                    self.app_state.home_selected = Some(match self.app_state.home_selected {
                        None => 0,
                        Some(i) if i + 1 >= n => {
                            self.app_state.home_selected = None;
                            return;
                        }
                        Some(i) => i + 1,
                    });
                }
                KeyCode::Left | KeyCode::Char('h') => {
                    let carousel = self.plugin_manager.carousel_items();
                    let n = carousel.len();
                    if n == 0 {
                        return;
                    }
                    self.app_state.home_selected = Some(match self.app_state.home_selected {
                        None => n - 1,
                        Some(0) => {
                            self.app_state.home_selected = None;
                            return;
                        }
                        Some(i) => i - 1,
                    });
                }
                KeyCode::Enter => {
                    if let Some(ci) = self.app_state.home_selected {
                        self.activate_carousel_item(ci);
                    }
                }
                _ => {}
            },
            Some(idx) => match key.code {
                KeyCode::Esc => {
                    let consumed = self.plugin_manager.handle_key(idx, key);
                    if !consumed {
                        self.plugin_manager.shutdown_and_remove(idx);
                        self.app_state.home_selected = None;
                    }
                }
                KeyCode::Char('q') => {
                    // Instead of quitting, let the plugin handle 'q'. User can
                    // still quit via Ctrl+C or by pressing Esc then q.
                    self.plugin_manager.handle_key(idx, key);
                }
                _ if key.code == self.bindings.about.0
                    && key.modifiers.contains(self.bindings.about.1) =>
                {
                    self.app_state.show_about = true;
                }
                _ => {
                    self.plugin_manager.handle_key(idx, key);
                }
            },
        }
    }
}
