use crossterm::event::{KeyCode, KeyEvent};
use ratatui::Frame;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span, Text};
use ratatui::widgets::ListItem;
use crate::app::App;
use super::chrome;
pub fn render(f: &mut Frame, app: &App) {
let area = crate::ui::centered(f.area(), chrome::WIDE.0, chrome::WIDE.1);
let dim = Style::default().fg(app.theme.fg_dim);
let rows = &app.research_stage_rows;
let mut items: Vec<ListItem> = Vec::new();
let pending: Vec<&(usize, String)> = app
.research_steer_log
.iter()
.filter(|(pos, _)| !app.research_steer_acked.contains(pos))
.collect();
let has_pending = !pending.is_empty();
if has_pending {
items.push(ListItem::new(Line::from(Span::styled(
"queued steers — picked up at the next round boundary:",
Style::default()
.fg(app.theme.accent)
.add_modifier(Modifier::BOLD),
))));
for (_, s) in pending {
items.push(ListItem::new(Line::from(vec![
Span::styled("● ", Style::default().fg(app.theme.accent)),
Span::styled(s.clone(), dim),
])));
}
items.push(ListItem::new(Line::from("")));
}
if rows.is_empty() && !has_pending {
items.push(ListItem::new(Line::from(Span::styled(
"waiting for the first update…",
dim,
))));
} else {
for content in rows.iter().rev() {
let (label, detail) = content.split_once(':').unwrap_or((content.as_str(), ""));
let detail = detail.trim();
let (glyph, color, detail) = if let Some(rest) = detail.strip_prefix("done —") {
("✓", app.theme.success, rest.trim())
} else if let Some(rest) = detail.strip_prefix("error —") {
("×", app.theme.error, rest.trim())
} else if let Some(rest) = detail.strip_prefix("working —") {
("●", app.theme.accent, rest.trim())
} else {
("○", app.theme.fg_dim, detail)
};
let mut lines = vec![Line::from(vec![
Span::styled(format!("{glyph} "), Style::default().fg(color)),
Span::styled(
label.to_string(),
Style::default().fg(color).add_modifier(Modifier::BOLD),
),
])];
for detail_line in detail.lines() {
lines.push(Line::from(vec![
Span::raw(" "),
Span::styled(detail_line.to_string(), dim),
]));
}
items.push(ListItem::new(Text::from(lines)));
}
}
let inner = chrome::render_frame(
f,
area,
chrome::input_title(
app,
"research agents · steer",
&app.research_live_input,
"type instruction · Enter send · Ctrl+↑ agents · Ctrl+X stop · Esc close",
),
&app.theme,
true,
chrome::Tone::Normal,
);
let list = chrome::standard_list(items, &app.theme);
f.render_widget(list, inner);
}
pub fn handle_key(app: &mut App, key: KeyEvent) {
let ctrl = key
.modifiers
.contains(crossterm::event::KeyModifiers::CONTROL);
match key.code {
KeyCode::Char('x') if ctrl => app.stop_research(),
KeyCode::Esc => app.popup = crate::app::Popup::None,
KeyCode::Enter => {
let text = app.research_live_input.trim().to_string();
app.research_live_input.clear();
app.steer_research(&text);
}
KeyCode::Backspace => {
app.research_live_input.pop();
}
KeyCode::Char(c) => app.research_live_input.push(c),
_ => {}
}
}