use std::any::Any;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use egui::{ScrollArea, Ui, WidgetText};
use egui_extras::{Size, StripBuilder};
use egui_file::FileDialog;
use egui_tiles::TileId;
use common::formats::binary_dse::DseExecutable;
use disassembler::{disassemble, Disassembly};
use crate::ui::components::Component;
use crate::ui::debugger::Action;
use crate::ui::debugger::panels::TilePane;

pub struct Disassembler {
    visible: bool,
    dialog: Option<FileDialog>,
    error: Option<String>,

    program: Option<DseExecutable>,
    disassembled: Option<Disassembly>,
}

impl TilePane for Disassembler {
    fn title(&self) -> WidgetText {
        "Disassembler".into()
    }

    fn ui(&mut self, ui: &mut Ui, _tile_id: TileId) -> Option<Action> {
        Component::ui(self, ui);
        None
    }

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

impl Disassembler {
    pub(crate) fn new() -> Self {
        Self {
            visible: true,
            dialog: None,
            error: None,

            program: None,
            disassembled: None,
        }
    }

    pub fn new_open(path: &Path) -> Self {
        let reader =  File::open(path).unwrap();
        let bin = DseExecutable::read(&mut BufReader::new(reader)).unwrap();

        Self {
            visible: true,
            dialog: None,
            error: None,
            program: Some(bin),
            disassembled: None,
        }
    }

    fn open(&mut self) {
        let Ok(cwd) = std::env::current_dir() else {
            self.error = Some("Couldn't get CWD to open file!".to_string());
            return;
        };

        if self.dialog.is_none() {
            let mut dialog = FileDialog::open_file();
            dialog.set_path(cwd);
            dialog.open();
            self.dialog = Some(dialog);
        }
    }

    fn handle_file_dialog(&mut self, ui: &mut Ui) {

        let Some(dialog) = &mut self.dialog else {
            return;
        };

        if !dialog.show(ui).selected() { return };

        let Some(file) = dialog.path() else {
            return
        };

        if !file.extension().is_some_and(|ext| ext == "dsb") {
            return
        }

        let reader = match File::open(file) {
            Ok(f) => f,
            Err(e) => {
                self.error = Some(e.to_string());
                return;
            }
        };

        match DseExecutable::read(&mut BufReader::new(reader)) {
            Ok(bin) =>  self.program = Some(bin),
            Err(e) => {
                self.error = Some(e.to_string());
                return;
            }
        };

        self.dialog = None;
    }
}

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

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

    fn ui(&mut self, ui: &mut egui::Ui) {
        self.handle_file_dialog(ui);

        ui.horizontal(|ui| {
            ui.spacing_mut().button_padding = egui::vec2(8.0, 4.0);
            ui.spacing_mut().item_spacing.x = 6.0;

            // Opens a file
            // ui.add_enabled(false, egui::Button::new("Open"));
            if ui.button("Open").clicked() {
                self.open();
            }
        });


        if let Some(binary) = &self.program {
            if let Some(output) = &self.disassembled {
                StripBuilder::new(ui)
                    .size(Size::exact(350.0))
                    .size(Size::remainder().at_most(500.0))
                    .horizontal(|mut strip| {

                        strip.cell(|ui| {
                            ScrollArea::vertical()
                                .id_salt("symbols")
                                .show(ui, |ui| {
                                    egui::Grid::new("symbols_grid")
                                        .striped(true)
                                        .spacing([12.0, 2.0]) // horizontal, vertical spacing
                                        .show(ui, |ui| {
                                            // Header
                                            ui.strong("Addr");
                                            ui.strong("Name");
                                            ui.strong("Section");
                                            ui.strong("Bind");
                                            ui.end_row();

                                            // Rows
                                            for symbol in &output.symbols {
                                                ui.monospace(format!("{:#06x}", symbol.address));
                                                ui.monospace(&symbol.name);
                                                ui.label(format!("{:?}", symbol.section));
                                                ui.label(format!("{:?}", symbol.binding));

                                                ui.end_row();
                                            }
                                        });
                                });
                        });

                        strip.cell(|ui| {
                            ScrollArea::vertical()
                                .id_salt("asm")
                                .show(ui, |ui| {
                                    egui::Grid::new("asm_grid")
                                        .striped(true)
                                        .spacing([12.0, 2.0])
                                        .show(ui, |ui| {
                                            for (addr, line) in output.text_lines.iter().enumerate() {
                                                ui.label(
                                                    egui::RichText::new(format!("{:04X}", addr))
                                                        .monospace()
                                                        .weak(),
                                                );

                                                ui.monospace(line);

                                                ui.end_row();
                                            }
                                        });
                                });
                        });
                    });


                // ui.horizontal(|ui| {
                //
                //     egui::ScrollArea::vertical()
                //         .id_salt("symbols_scroll")
                //         .show(ui, |ui| {
                //
                //         });
                //
                //     ui.separator();
                //
                //     egui::ScrollArea::vertical()
                //         .id_salt("asm_scroll")
                //         .show(ui, |ui| {
                //
                //         });
                // });
            } else {
                self.disassembled = Some(disassemble(&binary))
            }
        }
    }
}