use std::any::Any;
use std::num::ParseIntError;
use egui::{Ui, WidgetText};
use egui_extras::{Column, TableBuilder};
use egui_tiles::{Tile, TileId};
use common::prelude::Instruction;
use emulator_core::EmulatorHandle;
use emulator_core::memory::ram::MemoryBank;
use crate::ui::Action;
use crate::ui::panels::TilePane;

pub struct MemoryInspector {
    emulator: EmulatorHandle,

    view_size: u32,
    view_addr: u32,
    addr_input: String,

    // settings
    memory_viewer: MemoryViewer
}

impl MemoryInspector {
    #[must_use]
    pub fn new(emulator: EmulatorHandle) -> Self {
        Self {
            emulator,
            view_size: 1024,
            view_addr: 0,
            addr_input: String::from("0x00"),
            memory_viewer: MemoryViewer::new()
        }
    }
}


impl TilePane for MemoryInspector {
    fn title(&self) -> WidgetText {
        "Memory Inspector".into()
    }
    fn ui(&mut self, ui: &mut Ui, _tile_id: TileId) -> Option<Action> {

        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() && ui.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)");
        });

        let window = self.emulator.mem_read(self.view_addr, self.view_size);
        self.memory_viewer.ui(ui, &window, self.view_addr as usize);
        None
    }


    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}


pub struct MemoryViewer {
    show_bytes: bool,
    show_words: bool,
    show_ascii: bool,
    show_instruction: bool,
    show_decimal: bool,
}

impl MemoryViewer {
    pub fn new() -> Self {
        Self {
            show_bytes: true,
            show_words: true,
            show_ascii: true,
            show_instruction: true,
            show_decimal: true,
        }
    }

    pub fn ui(&mut self, ui: &mut egui::Ui, memory: &[u8], offset: usize) {
        egui::ScrollArea::vertical()
            .auto_shrink([false; 2])
            .id_salt("memory_inspector_scroll")
            .show(ui, |ui| {
                ui.horizontal(|ui| {
                    ui.toggle_value(&mut self.show_bytes, "Bytes");
                    ui.toggle_value(&mut self.show_words, "Words");
                    ui.toggle_value(&mut self.show_decimal, "Decimal");
                    ui.toggle_value(&mut self.show_ascii, "Ascii");
                    ui.toggle_value(&mut self.show_instruction, "Instructions");
                });

                ui.separator();

                let mut table = TableBuilder::new(ui)
                    .resizable(false) // makes all columns resizable at once
                    .column(Column::initial(75.0)); // addr

                if self.show_bytes {
                    table = table.column(Column::initial(90.0));
                }
                if self.show_words {
                    table = table.column(Column::initial(75.0));
                }
                if self.show_decimal {
                    table = table.column(Column::initial(80.0));
                }
                if self.show_ascii {
                    table = table.column(Column::initial(50.0));
                }
                if self.show_instruction {
                    table = table.column(Column::initial(200.0).clip(true));
                }

                table
                    .header(20.0, |mut header| {
                        header.col(|ui| {
                            ui.label("Addr");
                        });
                        if self.show_bytes {
                            header.col(|ui| {
                                ui.label("Bytes");
                            });
                        }
                        if self.show_words {
                            header.col(|ui| {
                                ui.label("Word");
                            });
                        }
                        if self.show_decimal {
                            header.col(|ui| {
                                ui.label("Decimal");
                            });
                        }
                        if self.show_ascii {
                            header.col(|ui| {
                                ui.label("Ascii");
                            });
                        }
                        if self.show_instruction {
                            header.col(|ui| {
                                ui.label("Instruction");
                            });
                        }
                    })
                    .body(|mut body| {
                        // Process bytes in chunks of 4
                        for (line_num, chunk) in memory.as_chunks::<4>().0.iter().enumerate() {
                            body.row(18.0, |mut row| {
                                let address = line_num * 4 + offset;

                                let value = u32::from_le_bytes(*chunk);

                                // Address column
                                row.col(|ui| {
                                    ui.label(
                                        egui::RichText::new(format!("0x{address:08X}"))
                                            .font(egui::FontId::monospace(12.0)),
                                    );
                                });

                                if self.show_bytes {
                                    row.col(|ui| {
                                        // Individual bytes column
                                        ui.label(
                                            egui::RichText::new(
                                                chunk
                                                    .iter()
                                                    .map(|b| format!("{b:02X}"))
                                                    .collect::<Vec<_>>()
                                                    .join(" "),
                                            )
                                                .font(egui::FontId::monospace(12.0))
                                                .color(egui::Color32::from_rgb(200, 200, 255)),
                                        );
                                    });
                                }

                                if self.show_words {
                                    row.col(|ui| {
                                        // Hex column
                                        ui.label(
                                            egui::RichText::new(format!("0x{value:08X}"))
                                                .font(egui::FontId::monospace(12.0))
                                                .color(egui::Color32::from_rgb(255, 100, 100)),
                                        );
                                    });
                                }

                                if self.show_decimal {
                                    row.col(|ui| {
                                        ui.label(
                                            egui::RichText::new(format!("{value}"))
                                                .font(egui::FontId::monospace(12.0))
                                                .color(egui::Color32::from_rgb(100, 255, 100)),
                                        );
                                    });
                                }

                                if self.show_ascii {
                                    row.col(|ui| {
                                        ui.label(
                                            egui::RichText::new(String::from_utf8_lossy(chunk))
                                                .font(egui::FontId::monospace(12.0))
                                                .color(egui::Color32::from_rgb(100, 255, 255)),
                                        );
                                    });
                                }

                                if self.show_instruction {
                                    row.col(|ui| {
                                        ui.label(
                                            egui::RichText::new(format!(
                                                "{:?}",
                                                Instruction(value)
                                            ))
                                                .font(egui::FontId::monospace(12.0))
                                                .color(egui::Color32::from_rgb(255, 100, 255)),
                                        );
                                    });
                                }
                            })
                        }
                    });
            });
    }
}

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>()
}

