use crate::emulator::system::model::{Command, Running, State, StateUpdate};
use std::sync::mpsc::{Receiver, Sender};

pub trait Component {
    fn render(&mut self, state: &mut State, ui: &mut egui::Ui, ctx: &egui::Context);
    fn visible(&mut self) -> &mut bool;
    fn name(&self) -> &'static str;
    fn category(&self) -> Category;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Category {
    Control,
    Memory,
    IO,
    Programming,
}

impl Category {
    #[must_use]
    pub const fn as_str(&self) -> &'static str {
        match self {
            Self::Control => "Control Systems",
            Self::Memory => "Memory Systems",
            Self::IO => "I/O Systems",
            Self::Programming => "Programming",
        }
    }

    #[must_use]
    pub fn list() -> Vec<Self> {
        vec![Self::Control, Self::Memory, Self::IO, Self::Programming]
    }
}

pub struct EmulatorUI {
    pub state: State,
    pub components: Vec<Box<dyn Component>>,
}

impl EmulatorUI {
    #[must_use]
    pub fn new(sender: Sender<Command>, receiver: Receiver<StateUpdate>) -> Self {
        Self {
            state: State::new(sender, receiver),
            components: vec![],
        }
    }

    pub fn add_component(&mut self, component: Box<dyn Component>) {
        self.components.push(component);
    }
}

impl eframe::App for EmulatorUI {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        if let Err(e) = self.state.update() {
            self.state.error_log.push(e.to_string());
        }

        if self.state.running == Running::Running {
            ctx.request_repaint();
        }

        egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
            ui.with_layout(
                egui::Layout::top_down_justified(egui::Align::Center)
                    .with_main_align(egui::Align::Min),
                |ui| {
                    ui.allocate_space(egui::vec2(0.0, 15.0));
                    ui.heading("DSA Simulator (Damn Simple Architecture 🔥)");
                    ui.allocate_space(egui::vec2(0.0, 15.0));
                },
            );
        });

        egui::CentralPanel::default().show(ctx, |ui| {
            ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |_ui| {
                egui::Window::new("Main Menu")
                    .resizable(false)
                    .default_width(300.0)
                    .show(ctx, |ui| {
                        super::menu::render_menu(self, ui, ctx);
                    });

                for c in &mut self.components {
                    let mut visible = *c.visible();
                    if visible {
                        egui::Window::new(c.name())
                            .open(&mut visible)
                            .show(ctx, |ui| {
                                c.render(&mut self.state, ui, ctx);
                            });
                    }
                    *c.visible() = visible;
                }
            });
        });

        egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| {
            ui.horizontal_centered(|ui| {
                ui.group(|ui| {
                    ui.add_space(10.0);
                    ui.strong("Authors:");
                    ui.add_space(5.0);
                    ui.label("zxq5");
                    ui.label("nullndvoid");
                    ui.add_space(10.0);
                    ui.separator();
                    ui.add_space(10.0);
                    ui.strong("Version");
                    ui.add_space(5.0);
                    ui.label("1.0.0");
                    ui.add_space(10.0);
                    ui.separator();
                    ui.add_space(10.0);
                    ui.strong("Source:");
                    ui.add_space(5.0);
                    ui.hyperlink_to(
                        "https://git.zxq5.dev/LowLevelDevs/damn_simple_architecture",
                        "https://git.zxq5.dev/LowLevelDevs/damn_simple_architecture",
                    );
                    ui.add_space(10.0);
                });
            });
        });
    }
}
