use eframe::emath::Vec2;
use egui::{Color32, Frame, Stroke};
use egui::widget_style::{Classes, WidgetState};
use emulator_core::processor::RunningState;

pub struct PaddedWidget {
    text: String,
    color: Option<Color32>,
    padding: Option<Vec2>,
    widget_type: WidgetType
}

enum WidgetType {
    Button,
    Indicator,
    Label
}

impl PaddedWidget {
    pub fn button(text: impl AsRef<str>) -> Self {
        Self {
            text: text.as_ref().to_string(),
            color: None,
            padding: None,
            widget_type: WidgetType::Button
        }
    }

    pub fn indicator(i: impl StatusIndicator) -> Self {
        Self {
            text: i.label().to_string(),
            color: Some(i.color()),
            padding: None,
            widget_type: WidgetType::Indicator
        }
    }

    pub fn label(text: String) -> Self {
        Self {
            text,
            color: None,
            padding: None,
            widget_type: WidgetType::Label
        }
    }

    pub fn color(&mut self, color: Color32) -> &mut Self {
        self.color = Some(color);
        self
    }

    pub fn padding(&mut self, padding: Vec2) -> &mut Self {
        self.padding = Some(padding);
        self
    }

    pub fn ui(&mut self, ui: &mut egui::Ui) -> egui::Response {
        let text: egui::WidgetText = self.text.clone().into();
        let galley = text.into_galley(ui, None, f32::INFINITY, egui::TextStyle::Button);
        let desired_size = galley.size() + self.padding.unwrap_or(Vec2::new(14.0, 8.0)) * 2.0;

        let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::click());

        if ui.is_rect_visible(rect) {
            // picks noninteractive/inactive/hovered/active automatically based on `response`

            let visuals = match self.widget_type {
                WidgetType::Button => ui.style().interact(&response),
                _ => &ui.visuals().widgets.inactive,
            };

            ui.painter().rect(
                rect,
                visuals.corner_radius,
                visuals.bg_fill,
                visuals.bg_stroke,
                egui::StrokeKind::Inside,
            );

            let text_pos = rect.center() - galley.size() / 2.0;
            ui.painter().galley(text_pos, galley, self.color.unwrap_or(visuals.fg_stroke.color));
        }

        response
    }
}

// pub fn frame_button(ui: &mut egui::Ui, text: impl Into<egui::WidgetText>, color: egui::Color32, padding: Vec2) -> egui::Response {
//     let text: egui::WidgetText = text.into();
//     let galley = text.into_galley(ui, None, f32::INFINITY, egui::TextStyle::Button);
//     let desired_size = galley.size() + padding * 2.0;
//
//     let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
//
//     if ui.is_rect_visible(rect) {
//         // picks noninteractive/inactive/hovered/active automatically based on `response`
//         let visuals = ui.style().interact(&response);
//
//         ui.painter().rect(
//             rect,
//             visuals.corner_radius,
//             visuals.bg_fill,
//             visuals.bg_stroke,
//             egui::StrokeKind::Inside,
//         );
//
//         let text_pos = rect.center() - galley.size() / 2.0;
//         ui.painter().galley(text_pos, galley, color);
//     }
//
//     response
// }
//
// pub fn info_field(ui: &mut egui::Ui, text: impl Into<egui::WidgetText>, padding: egui::Vec2) -> egui::Response {
//     let text: egui::WidgetText = text.into();
//     let galley = text.into_galley(ui, None, f32::INFINITY, egui::TextStyle::Button);
//     let desired_size = galley.size() + padding * 2.0;
//
//     let (rect, response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
//
//     if ui.is_rect_visible(rect) {
//         // Always use `inactive` — no hover highlight, no active/pressed feedback either.
//         // Response is still fully clickable; this only affects what gets drawn.
//         let visuals = &ui.visuals().widgets.inactive;
//
//         ui.painter().rect(
//             rect,
//             visuals.corner_radius,
//             visuals.bg_fill,
//             visuals.bg_stroke,
//             egui::StrokeKind::Inside,
//         );
//
//         let text_pos = rect.center() - galley.size() / 2.0;
//         ui.painter().galley(text_pos, galley, visuals.fg_stroke.color);
//     }
//
//     response
// }


pub fn bordered_frame<R>(
    ui: &mut egui::Ui,
    padding: egui::Vec2,
    add_contents: impl FnOnce(&mut egui::Ui) -> R,
) -> egui::InnerResponse<R> {
    let visuals = ui.visuals().widgets.inactive; // same visuals a normal button uses

    egui::Frame::new()
        .inner_margin(egui::Margin::symmetric(padding.x as i8, padding.y as i8))
        .stroke(visuals.bg_stroke)
        .corner_radius(visuals.corner_radius)
        .fill(visuals.bg_fill)
        .show(ui, add_contents)
}

pub trait StatusIndicator {
    fn ui(&mut self, ui: &mut egui::Ui, padding: egui::Vec2) -> egui::Response {
        bordered_frame(ui, padding, |ui| {
            ui.horizontal(|ui| {
                let dot_size = 8.0;
                let (rect, _) = ui.allocate_exact_size(
                    egui::vec2(dot_size, dot_size),
                    egui::Sense::hover(),
                );
                ui.painter().circle_filled(rect.center(), dot_size / 2.0, self.color());
                ui.label( self.label() );
            })
                .response
        })
            .response
    }


    fn color(&self) -> egui::Color32;

    fn label(&self) -> String;
}



impl StatusIndicator for RunningState {
    fn color(&self) -> egui::Color32 {
        match self {
            RunningState::Running => egui::Color32::from_rgb(0x4c, 0xaf, 0x50),
            RunningState::Paused => egui::Color32::from_rgb(0xff, 0xc1, 0x07),
            RunningState::Halted => egui::Color32::from_rgb(0xff, 0xc1, 0x07),
            RunningState::Breakpoint(_) => egui::Color32::from_rgb(0xe5, 0x39, 0x35),
            RunningState::Shutdown => egui::Color32::from_rgb(0xff, 0xc1, 0x07),
        }
    }

    fn label(&self) -> String {
        match self {
            RunningState::Running => "Running".into(),
            RunningState::Paused => "Paused".into(),
            RunningState::Halted => "Halted".into(),
            RunningState::Breakpoint(addr) => format!("Breakpoint @ {addr:#06x}"),
            RunningState::Shutdown => "Shutdown".into(),
        }
    }
}