use crate::emulator::{
    system::model::{Command, State},
    ui::interface::{Category, Component},
};

use eframe::egui;
use egui::{Color32, FontId, Vec2};

const VGA_WIDTH: usize = 80;
const VGA_HEIGHT: usize = 25;

pub struct Display {
    visible: bool,
}

impl Display {
    #[must_use]
    pub const fn new() -> Self {
        Self { visible: false }
    }
}

impl Default for Display {
    fn default() -> Self {
        Self::new()
    }
}

impl Component for Display {
    fn name(&self) -> &'static str {
        "Display"
    }

    fn category(&self) -> Category {
        Category::IO
    }

    fn visible(&mut self) -> &mut bool {
        &mut self.visible
    }

    fn render(&mut self, state: &mut State, ui: &mut egui::Ui, _ctx: &egui::Context) {
        state.send(Command::DisplayRequest);

        let display: Vec<u8> = state.display_view.clone();
        let font_id = FontId::monospace(12.0);

        let char_width = ui.fonts(|f| f.glyph_width(&font_id, 'W'));
        let line_height = ui.fonts(|f| f.row_height(&font_id));

        #[expect(clippy::cast_precision_loss)]
        let display_size = Vec2::new(
            char_width * VGA_WIDTH as f32,
            line_height * VGA_HEIGHT as f32,
        );

        let (rect, _response) = ui.allocate_exact_size(display_size, egui::Sense::all());

        // Fill background
        // ui.painter().rect_filled(rect, 0.0, Color32::BLACK);

        // Draw text
        for y in 0..VGA_HEIGHT {
            let mut row_text = String::with_capacity(VGA_WIDTH);
            for x in 0..VGA_WIDTH {
                let index = y * VGA_WIDTH + x;
                if index < display.len() {
                    let byte = display[index];
                    let ch = if (32..=126).contains(&byte) {
                        byte as char
                    } else {
                        ' '
                    };
                    row_text.push(ch);
                } else {
                    row_text.push(' ');
                }
            }

            #[expect(clippy::cast_precision_loss)]
            let text_pos = rect.min + Vec2::new(0.0, y as f32 * line_height);

            ui.painter().text(
                text_pos,
                egui::Align2::LEFT_TOP,
                row_text,
                font_id.clone(),
                Color32::WHITE,
            );
        }
    }
}
