//! GPU text rendering for terminal cells.
//!
//! Uses alacritty_terminal::Term for the VT state machine and renders each cell
//! as GPUI text elements. This is the "revolution" — no DOM, no Canvas 2D,
//! just GPU-accelerated glyph rendering at 120fps.
//!
//! Architecture:
//! 1. `vte::ansi::Processor` parses raw PTY bytes
//! 2. `alacritty_terminal::Term` (implements `vte::ansi::Handler`) processes escape sequences
//! 3. Grid cells are read via `grid[Line(i)][Column(j)]`
//! 4. Each cell is rendered as a GPUI div with the correct foreground color

use alacritty_terminal::event::{Event as AlacrittyEvent, EventListener};
use alacritty_terminal::grid::Dimensions;
use alacritty_terminal::index::{Column, Line};
use alacritty_terminal::term::Config as TermConfig;
use alacritty_terminal::term::Term;
use alacritty_terminal::vte::ansi::{Color, NamedColor, Processor};
use gpui::*;
use std::sync::{Arc, Mutex};

use crate::theme;

// ── Alacritty Event Listener (no-op for prototype) ──────────────────

struct GpuiTermEventListener;

impl EventListener for GpuiTermEventListener {
    fn send_event(&self, _event: AlacrittyEvent) {
        // In a full implementation, forward bell, title changes, etc.
    }
}

// ── ANSI Color Mapping ──────────────────────────────────────────────

/// Map alacritty's Color to Catppuccin Mocha Rgba.
fn ansi_to_rgba(color: Color) -> Rgba {
    match color {
        Color::Named(named) => named_to_rgba(named),
        Color::Spec(rgb) => Rgba {
            r: rgb.r as f32 / 255.0,
            g: rgb.g as f32 / 255.0,
            b: rgb.b as f32 / 255.0,
            a: 1.0,
        },
        Color::Indexed(idx) => {
            if idx < 16 {
                // Map standard 16 colors to named
                match idx {
                    0 => theme::SURFACE0,
                    1 => theme::RED,
                    2 => theme::GREEN,
                    3 => theme::YELLOW,
                    4 => theme::BLUE,
                    5 => theme::MAUVE,
                    6 => theme::TEAL,
                    7 => theme::SUBTEXT1,
                    8 => theme::OVERLAY0,
                    9 => theme::FLAMINGO,
                    10 => theme::GREEN,
                    11 => theme::YELLOW,
                    12 => theme::SAPPHIRE,
                    13 => theme::PINK,
                    14 => theme::SKY,
                    15 => theme::TEXT,
                    _ => theme::TEXT,
                }
            } else {
                // 216-color cube + 24 grayscale — approximate for prototype
                theme::TEXT
            }
        }
    }
}

fn named_to_rgba(named: NamedColor) -> Rgba {
    match named {
        NamedColor::Black => theme::SURFACE0,
        NamedColor::Red => theme::RED,
        NamedColor::Green => theme::GREEN,
        NamedColor::Yellow => theme::YELLOW,
        NamedColor::Blue => theme::BLUE,
        NamedColor::Magenta => theme::MAUVE,
        NamedColor::Cyan => theme::TEAL,
        NamedColor::White => theme::TEXT,
        NamedColor::BrightBlack => theme::OVERLAY0,
        NamedColor::BrightRed => theme::FLAMINGO,
        NamedColor::BrightGreen => theme::GREEN,
        NamedColor::BrightYellow => theme::YELLOW,
        NamedColor::BrightBlue => theme::SAPPHIRE,
        NamedColor::BrightMagenta => theme::PINK,
        NamedColor::BrightCyan => theme::SKY,
        NamedColor::BrightWhite => theme::TEXT,
        NamedColor::Foreground => theme::TEXT,
        NamedColor::Background => theme::BASE,
        NamedColor::Cursor => theme::ROSEWATER,
        NamedColor::DimForeground => theme::SUBTEXT0,
        _ => theme::TEXT,
    }
}

// ── Terminal Size Adapter ───────────────────────────────────────────

struct TerminalSize {
    cols: usize,
    rows: usize,
}

impl Dimensions for TerminalSize {
    fn total_lines(&self) -> usize {
        self.rows
    }
    fn screen_lines(&self) -> usize {
        self.rows
    }
    fn columns(&self) -> usize {
        self.cols
    }
    fn last_column(&self) -> Column {
        Column(self.cols.saturating_sub(1))
    }
    fn bottommost_line(&self) -> Line {
        Line(self.rows as i32 - 1)
    }
    fn topmost_line(&self) -> Line {
        Line(0)
    }
}

// ── Terminal State ──────────────────────────────────────────────────

/// Wraps alacritty_terminal::Term with render cache for GPUI.
pub struct TerminalState {
    term: Term<GpuiTermEventListener>,
    processor: Processor,
    pub cols: usize,
    pub rows: usize,
    /// Cached render data: Vec of rows, each row is Vec of (char, fg_color).
    render_lines: Vec<Vec<(char, Rgba)>>,
}

impl TerminalState {
    pub fn new(cols: usize, rows: usize) -> Self {
        let size = TerminalSize { cols, rows };
        let config = TermConfig::default();
        let term = Term::new(config, &size, GpuiTermEventListener);
        let processor = Processor::new();

        Self {
            term,
            processor,
            cols,
            rows,
            render_lines: Vec::new(),
        }
    }

    /// Feed raw PTY output bytes into the VT state machine.
    pub fn process_output(&mut self, data: &[u8]) {
        self.processor.advance(&mut self.term, data);
    }

    /// Rebuild the render_lines cache from the term grid.
    pub fn update_render_cache(&mut self) {
        let grid = self.term.grid();
        self.render_lines.clear();

        for row_idx in 0..self.rows {
            let mut line = Vec::with_capacity(self.cols);
            let row = &grid[Line(row_idx as i32)];
            for col_idx in 0..self.cols {
                let cell = &row[Column(col_idx)];
                let ch = cell.c;
                let fg = ansi_to_rgba(cell.fg);
                line.push((ch, fg));
            }
            self.render_lines.push(line);
        }
    }

    /// Get the cached render lines.
    pub fn lines(&self) -> &[Vec<(char, Rgba)>] {
        &self.render_lines
    }

    /// Get cursor position (row, col).
    pub fn cursor_point(&self) -> (usize, usize) {
        let cursor = self.term.grid().cursor.point;
        (cursor.line.0 as usize, cursor.column.0)
    }
}

// ── GPUI Terminal View ──────────────────────────────────────────────

/// GPUI view that renders the terminal grid.
/// Each cell is rendered as a text span with the correct foreground color.
/// The cursor is rendered as a block highlight.
pub struct TerminalView {
    pub state: TerminalState,
}

impl TerminalView {
    pub fn new(cols: usize, rows: usize) -> Self {
        Self {
            state: TerminalState::new(cols, rows),
        }
    }

    /// Feed demo content for visual testing.
    pub fn feed_demo(&mut self) {
        let demo = b"\x1b[1;34m~/code/ai/agent-orchestrator\x1b[0m $ \x1b[32mcargo build\x1b[0m\r\n\
            \x1b[33mCompiling\x1b[0m agor-core v0.1.0\r\n\
            \x1b[33mCompiling\x1b[0m agor-gpui v0.1.0\r\n\
            \x1b[1;32m  Finished\x1b[0m `dev` profile [unoptimized + debuginfo] in 4.2s\r\n\
            \x1b[1;34m~/code/ai/agent-orchestrator\x1b[0m $ \x1b[7m \x1b[0m";
        self.state.process_output(demo);
        self.state.update_render_cache();
    }
}

impl Render for TerminalView {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        // Update render cache from terminal state
        self.state.update_render_cache();
        let (cursor_row, cursor_col) = self.state.cursor_point();

        // Build rows as horizontal flex containers of character spans
        let mut rows: Vec<Div> = Vec::new();

        for (row_idx, line) in self.state.lines().iter().enumerate() {
            let mut row_div = div().flex().flex_row();

            for (col_idx, &(ch, fg)) in line.iter().enumerate() {
                let is_cursor = row_idx == cursor_row && col_idx == cursor_col;
                let display_char = if ch == '\0' || ch == ' ' {
                    ' '
                } else {
                    ch
                };

                let mut cell = div()
                    .w(px(8.4))
                    .h(px(18.0))
                    .flex()
                    .items_center()
                    .justify_center()
                    .text_size(px(14.0))
                    .text_color(fg);

                if is_cursor {
                    cell = cell.bg(theme::ROSEWATER).text_color(theme::BASE);
                }

                row_div = row_div.child(cell.child(format!("{}", display_char)));
            }

            rows.push(row_div);
        }

        // Terminal container
        let mut container = div()
            .w_full()
            .h_full()
            .bg(theme::BASE)
            .p(px(4.0))
            .flex()
            .flex_col()
            .overflow_hidden()
            .font_family("JetBrains Mono");

        for row in rows {
            container = container.child(row);
        }

        container
    }
}
