use super::state::{McPanel, McState};
use crate::tui::app::App;
use crate::tui::events::AppMode;
use crossterm::event::{KeyCode, KeyEvent};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyOutcome {
Consumed,
Close,
NotConsumed,
ApplySelected,
RejectSelected,
}
pub async fn handle_key(app: &mut App, key: KeyEvent) {
let count = panel_count(app);
match decide(&mut app.mc, count, key) {
KeyOutcome::Consumed | KeyOutcome::NotConsumed => {}
KeyOutcome::Close => {
app.mode = AppMode::Chat;
app.mc.detail_open = false;
}
KeyOutcome::ApplySelected => super::actions::apply_selected(app).await,
KeyOutcome::RejectSelected => super::actions::reject_selected(app).await,
}
}
pub fn decide(state: &mut McState, panel_item_count: usize, key: KeyEvent) -> KeyOutcome {
if state.detail_open {
decide_with_popup(state, panel_item_count, key)
} else {
decide_without_popup(state, panel_item_count, key)
}
}
fn decide_with_popup(state: &mut McState, panel_item_count: usize, key: KeyEvent) -> KeyOutcome {
match key.code {
KeyCode::Esc => {
state.detail_open = false;
KeyOutcome::Consumed
}
KeyCode::Up | KeyCode::Char('k') => {
move_selection(state, panel_item_count, -1);
KeyOutcome::Consumed
}
KeyCode::Down | KeyCode::Char('j') => {
move_selection(state, panel_item_count, 1);
KeyOutcome::Consumed
}
_ => KeyOutcome::NotConsumed,
}
}
fn decide_without_popup(state: &mut McState, panel_item_count: usize, key: KeyEvent) -> KeyOutcome {
match key.code {
KeyCode::Esc => KeyOutcome::Close,
KeyCode::Tab | KeyCode::Char('l') => {
state.focus_next();
KeyOutcome::Consumed
}
KeyCode::BackTab | KeyCode::Char('h') => {
state.focus_prev();
KeyOutcome::Consumed
}
KeyCode::Up | KeyCode::Char('k') => {
move_selection(state, panel_item_count, -1);
KeyOutcome::Consumed
}
KeyCode::Down | KeyCode::Char('j') => {
move_selection(state, panel_item_count, 1);
KeyOutcome::Consumed
}
KeyCode::Home | KeyCode::Char('g') => {
state.selected_index = 0;
KeyOutcome::Consumed
}
KeyCode::End | KeyCode::Char('G') => {
state.selected_index = panel_item_count.saturating_sub(1);
KeyOutcome::Consumed
}
KeyCode::Enter => {
if panel_item_count > 0 {
state.detail_open = true;
}
KeyOutcome::Consumed
}
KeyCode::Char('a') => {
if state.focused_panel == McPanel::Inbox && panel_item_count > 0 {
KeyOutcome::ApplySelected
} else {
KeyOutcome::Consumed
}
}
KeyCode::Char('r') => {
if state.focused_panel == McPanel::Inbox && panel_item_count > 0 {
KeyOutcome::RejectSelected
} else {
KeyOutcome::Consumed
}
}
_ => KeyOutcome::NotConsumed,
}
}
fn move_selection(state: &mut McState, count: usize, delta: i32) {
if count == 0 {
state.selected_index = 0;
return;
}
let max_idx = count - 1;
let cur = state.selected_index.min(max_idx) as i32;
let next = (cur + delta).clamp(0, max_idx as i32) as usize;
state.selected_index = next;
}
fn panel_count(app: &App) -> usize {
match app.mc.focused_panel {
McPanel::Inbox => crate::brain::mission_control::inbox_service::list().len(),
McPanel::Activity => app.mc.activity.len(),
McPanel::Schedule => app.mc.schedule.len(),
}
}