//! Componente `Input` rico (T-10): caixa de entrada estilo OpenCode com
//! placeholder, cursor visual e linha de modo.
//!
//! Puro, sem estado/IO e sem panic. Depende apenas de `theme::Theme` e
//! dos tipos públicos do `ratatui`.

#![allow(dead_code)]

use crate::tui::theme::Theme;
use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    style::{Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Paragraph, Wrap},
    Frame,
};

// ---------------------------------------------------------------------------
// Props
// ---------------------------------------------------------------------------

/// Propriedades de renderização do componente `Input`.
///
/// Sem estado próprio — o chamador mantém `value` e repassa a cada frame.
pub struct InputProps<'a> {
    /// Texto digitado pelo usuário (pode ser vazio).
    pub value: &'a str,
    /// Texto exibido quando `value` está vazio.
    pub placeholder: &'a str,
    /// Linha de contexto exibida abaixo do campo (ex.: "Build · GPT-5.3 · medium").
    pub mode_line: &'a str,
    /// Se `true`, a borda é colorida no acento primário e o cursor é exibido.
    pub focused: bool,
}

// ---------------------------------------------------------------------------
// Render
// ---------------------------------------------------------------------------

/// Renderiza o componente `Input` no `frame` dentro de `area`.
///
/// Layout interno (dentro de `area`):
/// - linha 0..n-1 : campo de texto com borda e prompt.
/// - linha n      : linha de modo opcional (sem borda, text_muted).
///
/// Quando `mode_line` está vazio, o campo ocupa toda a área. Se `area` for
/// muito pequena (< 2 linhas), apenas o campo é exibido — sem panic.
pub fn render(frame: &mut Frame, area: Rect, props: &InputProps, theme: &Theme) {
    // Protege contra área degenerada.
    if area.height == 0 || area.width == 0 {
        return;
    }

    // Divide a área verticalmente só quando há linha de modo.
    let has_mode_line = !props.mode_line.is_empty();
    let (field_area, mode_area) = if has_mode_line && area.height >= 2 {
        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Min(1), Constraint::Length(1)])
            .split(area);
        (chunks[0], Some(chunks[1]))
    } else {
        (area, None)
    };

    // --- Borda do campo ---
    let border_style = if props.focused {
        Style::default().fg(theme.primary)
    } else {
        Style::default().fg(theme.text_muted)
    };

    let block = Block::default()
        .borders(Borders::ALL)
        .border_style(border_style);

    // --- Conteúdo do campo (prompt + texto/placeholder + cursor) ---
    let prompt = Span::styled("> ", Style::default().fg(theme.text_muted));

    let content: Span = if props.value.is_empty() {
        Span::styled(
            props.placeholder.to_owned(),
            Style::default()
                .fg(theme.text_muted)
                .add_modifier(Modifier::ITALIC),
        )
    } else {
        Span::styled(
            props.value.to_owned(),
            Style::default().fg(theme.text_strong),
        )
    };

    let mut spans: Vec<Span> = vec![prompt, content];

    if props.focused {
        spans.push(Span::styled(
            "▏",
            Style::default()
                .fg(theme.primary)
                .add_modifier(Modifier::BOLD),
        ));
    }

    let field_paragraph = Paragraph::new(Line::from(spans))
        .block(block)
        .wrap(Wrap { trim: false });

    frame.render_widget(field_paragraph, field_area);

    // --- Linha de modo ---
    if let Some(mode_rect) = mode_area {
        if !props.mode_line.is_empty() {
            let mode_paragraph = Paragraph::new(Line::from(vec![Span::styled(
                props.mode_line.to_owned(),
                Style::default().fg(theme.text_muted),
            )]));
            frame.render_widget(mode_paragraph, mode_rect);
        }
    }
}

// ---------------------------------------------------------------------------
// Testes
// ---------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tui::theme::{theme, ColorDepth};
    use ratatui::{backend::TestBackend, Terminal};

    fn make_terminal(width: u16, height: u16) -> Terminal<TestBackend> {
        Terminal::new(TestBackend::new(width, height)).unwrap()
    }

    // --- value vazio → placeholder (80x5) ---

    #[test]
    fn render_empty_value_focused_80x5_sem_panic() {
        let mut terminal = make_terminal(80, 5);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 80, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "",
                        placeholder: "Digite sua ideia…",
                        mode_line: "Build · GPT-5.3 · medium",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    #[test]
    fn render_empty_value_unfocused_80x5_sem_panic() {
        let mut terminal = make_terminal(80, 5);
        let t = theme(ColorDepth::Ansi256);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 80, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "",
                        placeholder: "Digite sua ideia…",
                        mode_line: "Build · GPT-5.3 · medium",
                        focused: false,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    // --- value preenchido (80x5) ---

    #[test]
    fn render_with_value_focused_80x5_sem_panic() {
        let mut terminal = make_terminal(80, 5);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 80, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "Adicionar comando sdd review",
                        placeholder: "Digite sua ideia…",
                        mode_line: "Build · GPT-5.3 · medium",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    #[test]
    fn render_with_value_unfocused_80x5_sem_panic() {
        let mut terminal = make_terminal(80, 5);
        let t = theme(ColorDepth::Ansi16);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 80, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "Adicionar comando sdd review",
                        placeholder: "Digite sua ideia…",
                        mode_line: "Build · GPT-5.3 · medium",
                        focused: false,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    // --- 40x5 ---

    #[test]
    fn render_empty_value_focused_40x5_sem_panic() {
        let mut terminal = make_terminal(40, 5);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 40, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "",
                        placeholder: "Digite…",
                        mode_line: "medium",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    #[test]
    fn render_with_value_unfocused_40x5_sem_panic() {
        let mut terminal = make_terminal(40, 5);
        let t = theme(ColorDepth::Ansi256);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 40, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "Texto de teste",
                        placeholder: "Digite…",
                        mode_line: "medium",
                        focused: false,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    // --- área degenerada não causa panic ---

    #[test]
    fn render_area_zero_sem_panic() {
        let mut terminal = make_terminal(10, 3);
        let t = theme(ColorDepth::Ansi16);

        terminal
            .draw(|f| {
                // área com height=0: deve retornar imediatamente
                let area = Rect::new(0, 0, 0, 0);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "x",
                        placeholder: "p",
                        mode_line: "m",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    #[test]
    fn render_area_uma_linha_sem_panic() {
        let mut terminal = make_terminal(40, 1);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 40, 1);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "",
                        placeholder: "p",
                        mode_line: "m",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();
    }

    #[test]
    fn mode_line_vazio_usa_area_inteira_do_campo() {
        let mut terminal = make_terminal(40, 3);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 40, 3);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "",
                        placeholder: "Digite…",
                        mode_line: "",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();

        let buffer = terminal.backend().buffer().clone();
        let bottom_row_has_border =
            (0..40).any(|x| matches!(buffer[(x, 2)].symbol(), "└" | "┘" | "─"));
        assert!(
            bottom_row_has_border,
            "campo deve ocupar a altura total quando mode_line está vazio"
        );
    }

    // --- cursor presente apenas quando focused ---

    #[test]
    fn cursor_ausente_quando_unfocused() {
        let mut terminal = make_terminal(40, 5);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 40, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "texto",
                        placeholder: "p",
                        mode_line: "m",
                        focused: false,
                    },
                    &t,
                );
            })
            .unwrap();

        // O cursor "▏" é um char de 3 bytes UTF-8.
        // Como não há modo focused, nenhuma célula deve conter '▏'.
        let buffer = terminal.backend().buffer().clone();
        let has_cursor = buffer.content().iter().any(|cell| cell.symbol() == "▏");
        assert!(!has_cursor, "cursor não deve aparecer quando unfocused");
    }

    #[test]
    fn cursor_presente_quando_focused() {
        let mut terminal = make_terminal(40, 5);
        let t = theme(ColorDepth::TrueColor);

        terminal
            .draw(|f| {
                let area = Rect::new(0, 0, 40, 5);
                render(
                    f,
                    area,
                    &InputProps {
                        value: "texto",
                        placeholder: "p",
                        mode_line: "m",
                        focused: true,
                    },
                    &t,
                );
            })
            .unwrap();

        let buffer = terminal.backend().buffer().clone();
        let has_cursor = buffer.content().iter().any(|cell| cell.symbol() == "▏");
        assert!(has_cursor, "cursor deve aparecer quando focused");
    }
}
