use std::num::ParseIntError;

use common::prelude::Instruction;

use crate::{MemoryBank, frontend::components::Component};

pub struct MemoryInspector {
    memory: MemoryBank,

    view_size: u32,
    view_addr: u32,
    visible: bool,
    addr_input: String,
}

impl MemoryInspector {
    #[must_use]
    pub fn new(memory: MemoryBank) -> Self {
        Self {
            memory,
            view_size: 1024,
            view_addr: 0,
            visible: false,
            addr_input: String::from("0x00"),
        }
    }
}

impl Component for MemoryInspector {
    fn title(&self) -> &'static str {
        "Memory Inspector"
    }

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

    fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) {
        // Right column - Memory
        ui.vertical(|ui| {
            ui.heading("Memory Inspector");
            ui.add_space(10.0);

            // Address input section
            ui.horizontal(|ui| {
                ui.label("Address:");

                let address_response = ui.add(
                    egui::TextEdit::singleline(&mut self.addr_input)
                        .hint_text("0x1000 or 4096")
                        .desired_width(150.0),
                );

                ui.add_space(10.0);

                // Search button
                let search_clicked = ui.button("🔍 Search").clicked();

                // Handle Enter key in text field
                let enter_pressed =
                    address_response.lost_focus() && ctx.input(|i| i.key_pressed(egui::Key::Enter));

                if search_clicked || enter_pressed {
                    if let Ok(new) = parse_address(&self.addr_input) {
                        if new % 4 == 0 {
                            self.view_addr = new;
                        } else {
                            println!("Address must be 4-byte aligned");
                        }
                    } else {
                        println!("Invalid address");
                        // state.error_log.push("Invalid address".to_string());
                    }
                }

                ui.label("(hex or decimal)");
            });

            ui.add_space(10.0);

            // Memory table
            egui::ScrollArea::vertical()
                .auto_shrink(true)
                .id_salt("memory_inspector_scroll")
                .show(ui, |ui| {
                    egui::Grid::new("memory_grid")
                        .spacing([12.0, 2.0])
                        .min_col_width(5.0)
                        .striped(true)
                        .show(ui, |ui| {
                            // Header
                            ui.strong("Address");

                            for i in 0..4 {
                                ui.strong(format!("{i:X}"));
                            }

                            ui.strong("Decimal");
                            ui.strong("Instruction");

                            ui.end_row();

                            // Memory data (8 bytes per row)
                            for (offset, word) in (0..self.view_size / 4)
                                .map(|i| i * 4)
                                .map(|i| (i, self.memory.read_word(self.view_addr + i)))
                            {
                                let row_address = self.view_addr + offset;
                                ui.monospace(format!("0x{row_address:08X} ({row_address})"));
                                for byte in word.to_le_bytes() {
                                    ui.monospace(format!("{byte:02X}"));
                                }

                                ui.monospace(format!("{word}"));
                                ui.monospace(format!("{:?}", Instruction(word)));
                                ui.end_row();
                            }
                        });
                });
        });
    }
}

fn parse_address(address: &str) -> Result<u32, ParseIntError> {
    if let Some(hex_part) = address.strip_prefix("0x") {
        return u32::from_str_radix(hex_part, 16);
    }

    if let Some(bin_part) = address.strip_prefix("0b") {
        return u32::from_str_radix(bin_part, 2);
    }

    if let Some(oct_part) = address.strip_prefix("0o") {
        return u32::from_str_radix(oct_part, 8);
    }

    address.parse::<u32>()
}
