//! File/directory browser modal widget.

use crate::theme;
use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::{Color, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::Paragraph;
use ratatui::Frame;

use super::ModalFrame;

/// Modal listing files and directories with a filter input line.
pub struct FileBrowserModal<'a> {
    title: &'a str,
    input: &'a str,
    entries: &'a [(String, bool, bool)],
    selected: usize,
    scroll_offset: usize,
    border_color: Option<Color>,
    width: u16,
    height: u16,
}

impl<'a> FileBrowserModal<'a> {
    pub fn new(title: &'a str, input: &'a str, entries: &'a [(String, bool, bool)]) -> Self {
        Self {
            title,
            input,
            entries,
            selected: 0,
            scroll_offset: 0,
            border_color: None,
            width: 60,
            height: 16,
        }
    }

    pub fn selected(mut self, idx: usize) -> Self {
        self.selected = idx;
        self
    }

    pub fn scroll_offset(mut self, offset: usize) -> Self {
        self.scroll_offset = offset;
        self
    }

    pub fn border_color(mut self, c: Color) -> Self {
        self.border_color = Some(c);
        self
    }

    pub fn width(mut self, w: u16) -> Self {
        self.width = w;
        self
    }

    pub fn height(mut self, h: u16) -> Self {
        self.height = h;
        self
    }

    pub fn render_centered(self, frame: &mut Frame, term: Rect) -> Rect {
        let colors = theme::get();
        let border_color = self.border_color.unwrap_or(colors.ui.text_primary);

        let inner = ModalFrame::new(self.title)
            .width(self.width)
            .height(self.height)
            .border_color(border_color)
            .render_centered(frame, term);

        let rows = Layout::vertical([Constraint::Length(1), Constraint::Min(1)]).split(inner);

        // Input line
        frame.render_widget(
            Paragraph::new(Line::from(vec![
                Span::raw("> "),
                Span::styled(self.input, Style::new().fg(colors.input.text)),
                Span::styled("█", Style::new().fg(colors.input.cursor)),
            ])),
            rows[0],
        );

        // Entries list
        let visible_height = rows[1].height as usize;
        let visible_entries = self
            .entries
            .iter()
            .skip(self.scroll_offset)
            .take(visible_height);

        let lines: Vec<Line> = visible_entries
            .enumerate()
            .map(|(i, (name, is_dir, is_cagire))| {
                let abs_idx = i + self.scroll_offset;
                let is_selected = abs_idx == self.selected;
                let prefix = if is_selected { "> " } else { "  " };
                let display = if *is_dir {
                    format!("{prefix}{name}/")
                } else {
                    format!("{prefix}{name}")
                };
                let color = if is_selected {
                    colors.browser.selected
                } else if *is_dir {
                    colors.browser.directory
                } else if *is_cagire {
                    colors.browser.project_file
                } else {
                    colors.browser.file
                };
                Line::from(Span::styled(display, Style::new().fg(color)))
            })
            .collect();

        frame.render_widget(Paragraph::new(lines), rows[1]);

        inner
    }
}
