//! Bottom-pane `@file` fuzzy picker. Pure rendering; key handling is in
//! `update.rs::handle_file_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::FilePickerState;
use crate::theme;

/// borders(2) + query(1) + rows (1..8) + hint(1).
pub fn desired_height(state: &FilePickerState) -> u16 {
    let rows = (state.matches.len() as u16).clamp(1, 8);
    2 + 1 + rows + 1
}

pub fn render(state: &FilePickerState, frame: &mut Frame, area: Rect) {
    let block = Block::default()
        .title(" Files ")
        .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::Length(1),
            Constraint::Min(0),
            Constraint::Length(1),
        ])
        .split(inner);

    frame.render_widget(
        Paragraph::new(Line::from(vec![
            Span::styled("@", theme::assistant()),
            Span::raw(state.query.clone()),
        ])),
        chunks[0],
    );

    let mut body: Vec<Line> = Vec::new();
    if state.matches.is_empty() {
        body.push(Line::from(Span::styled("(no matching file)", theme::dim())));
    } else {
        for (idx, path) in state.matches.iter().take(8).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(path.clone(), style),
            ]));
        }
    }
    frame.render_widget(Paragraph::new(body), chunks[1]);

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

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

    fn state() -> FilePickerState {
        FilePickerState {
            query: "ma".into(),
            anchor_byte: 0,
            matches: vec!["src/main.rs".into(), "README.md".into()],
            selected: 0,
        }
    }

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

    #[test]
    fn desired_height_scales_with_matches() {
        assert_eq!(desired_height(&state()), 2 + 1 + 2 + 1);
        let empty = FilePickerState::default();
        assert_eq!(desired_height(&empty), 2 + 1 + 1 + 1);
    }
}
