//! Bottom-pane `/fork` picker. Pure rendering; keys in
//! `update.rs::handle_fork_picker_key`.

use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::Modifier;
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Paragraph};
use ratatui::Frame;

use crate::state::{ForkCandidate, ForkPickerState};
use crate::theme;

pub const MAX_ROWS: usize = 10;

pub fn desired_height(candidates: &[ForkCandidate]) -> u16 {
    let n = (candidates.len().min(MAX_ROWS) as u16).clamp(1, MAX_ROWS as u16);
    2 + n + 1
}

pub fn render(
    state: &ForkPickerState,
    candidates: &[ForkCandidate],
    frame: &mut Frame,
    area: Rect,
) {
    let block = Block::default()
        .title(" Fork from ")
        .borders(Borders::ALL)
        .border_style(theme::modal_border());
    let inner = block.inner(area);
    frame.render_widget(block, area);

    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([Constraint::Min(0), Constraint::Length(1)])
        .split(inner);

    let mut body: Vec<Line> = Vec::new();
    if candidates.is_empty() {
        body.push(Line::from(Span::styled(
            "(no earlier messages to fork from)",
            theme::dim(),
        )));
    } else {
        for (idx, c) in candidates.iter().take(MAX_ROWS).enumerate() {
            let selected = idx == state.selected;
            let marker = if selected { "› " } else { "  " };
            let style = if selected {
                theme::primary().add_modifier(Modifier::BOLD)
            } else {
                theme::primary()
            };
            body.push(Line::from(vec![
                Span::styled(
                    marker,
                    if selected {
                        theme::assistant()
                    } else {
                        theme::dim()
                    },
                ),
                Span::styled(c.preview.clone(), style),
            ]));
        }
    }
    frame.render_widget(Paragraph::new(body), chunks[0]);

    frame.render_widget(
        Paragraph::new(Line::from(vec![
            Span::styled("↑↓", theme::assistant()),
            Span::raw(" navigate  "),
            Span::styled("Enter", theme::assistant()),
            Span::raw(" pick  "),
            Span::styled("Esc", theme::error()),
            Span::raw(" cancel"),
        ])),
        chunks[1],
    );
}

#[cfg(test)]
mod tests {
    use super::*;
    use ratatui::backend::TestBackend;
    use ratatui::Terminal;

    fn candidates() -> Vec<ForkCandidate> {
        vec![
            ForkCandidate {
                id: "e3".into(),
                preview: "the third thing".into(),
            },
            ForkCandidate {
                id: "e1".into(),
                preview: "the first thing".into(),
            },
        ]
    }

    #[test]
    fn renders_fork_picker() -> Result<(), Box<dyn std::error::Error>> {
        let mut term = Terminal::new(TestBackend::new(60, 6))?;
        term.draw(|f| render(&ForkPickerState::default(), &candidates(), f, f.area()))?;
        insta::assert_snapshot!(term.backend());
        Ok(())
    }

    #[test]
    fn desired_height_scales_and_handles_empty() {
        assert_eq!(desired_height(&candidates()), 2 + 2 + 1);
        assert_eq!(desired_height(&[]), 2 + 1 + 1);
    }
}
