//! Action-returning Inspector component-card chrome shared by production and gallery fixtures.

use egui;
use egui_phosphor_icons::{icons, Icon};

use crate::design_system;
use crate::design_system::typography::TypeRole;
use crate::theme::{BORDER, ERROR, SELECTION, SUCCESS, TEXT, TEXT_DIM, TEXT_MUTED, WIDGET_BG};

pub const COMPONENT_HEADER_HEIGHT: f32 = 50.0;
const COMPONENT_RAIL_X: f32 = 7.0;
const COMPONENT_CARET_CENTER_X: f32 = 26.0;
const COMPONENT_ICON_CENTER_X: f32 = 51.0;
const COMPONENT_IDENTITY_X: f32 = 69.0;
const COMPONENT_ACTIONS_WIDTH: f32 = 104.0;

#[derive(Debug, Clone, Copy)]
pub struct ComponentCardOptions {
    pub type_name: &'static str,
    pub title: &'static str,
    pub icon: Icon,
    pub active_toggle: bool,
    pub removable: bool,
    pub reorderable: bool,
    pub resettable: bool,
    pub copyable: bool,
    pub summary: &'static str,
    pub body_margin: i8,
}

impl ComponentCardOptions {
    pub const fn removable(type_name: &'static str, title: &'static str, icon: Icon) -> Self {
        Self {
            type_name,
            title,
            icon,
            active_toggle: true,
            removable: true,
            reorderable: true,
            resettable: true,
            copyable: true,
            summary: "Authoring component",
            body_margin: 12,
        }
    }

    pub const fn fixed(type_name: &'static str, title: &'static str, icon: Icon) -> Self {
        Self {
            type_name,
            title,
            icon,
            active_toggle: false,
            removable: false,
            reorderable: false,
            resettable: true,
            copyable: false,
            summary: "Authoring component",
            body_margin: 12,
        }
    }
}

#[derive(Debug, Clone)]
pub struct ComponentCardViewModel {
    pub options: ComponentCardOptions,
    pub active: bool,
    pub collapsed: bool,
    pub pasteable: bool,
    pub can_move_up: bool,
    pub can_move_down: bool,
}

#[derive(Debug, Clone, Default)]
pub struct ComponentCardAction {
    pub type_name: &'static str,
    pub collapsed: Option<bool>,
    pub active: Option<bool>,
    pub reset: bool,
    pub copy: bool,
    pub paste: bool,
    pub move_up: bool,
    pub move_down: bool,
    pub remove: bool,
}

pub fn component_card(
    ui: &mut egui::Ui,
    view: &ComponentCardViewModel,
    add_contents: impl FnOnce(&mut egui::Ui),
) -> ComponentCardAction {
    let mut action = ComponentCardAction {
        type_name: view.options.type_name,
        ..Default::default()
    };
    design_system::scope(ui, |ui| {
        egui::Frame::new()
            .fill(WIDGET_BG)
            .stroke(egui::Stroke::new(1.0_f32, BORDER))
            .corner_radius(egui::CornerRadius::same(5))
            .show(ui, |ui| {
                let width = ui.available_width().max(1.0);
                let (header, response) = ui.allocate_exact_size(
                    egui::vec2(width, COMPONENT_HEADER_HEIGHT),
                    egui::Sense::click(),
                );
                ui.painter().rect_filled(
                    egui::Rect::from_min_size(
                        header.min + egui::vec2(COMPONENT_RAIL_X, 7.0),
                        egui::vec2(3.0, 36.0),
                    ),
                    2.0,
                    SELECTION,
                );
                let caret_rect = egui::Rect::from_center_size(
                    egui::pos2(header.left() + COMPONENT_CARET_CENTER_X, header.center().y),
                    egui::vec2(20.0, 28.0),
                );
                if ui
                    .put(
                        caret_rect,
                        egui::Button::new(icon_text(
                            if view.collapsed {
                                icons::CARET_RIGHT
                            } else {
                                icons::CARET_DOWN
                            },
                            12.0,
                        ))
                        .frame(false),
                    )
                    .clicked()
                {
                    action.collapsed = Some(!view.collapsed);
                }
                ui.painter().text(
                    egui::pos2(header.left() + COMPONENT_ICON_CENTER_X, header.center().y),
                    egui::Align2::CENTER_CENTER,
                    view.options.icon.as_str(),
                    egui::FontId::new(18.0, egui::FontFamily::Name("phosphor-bold".into())),
                    TEXT_DIM,
                );
                ui.painter().text(
                    egui::pos2(header.left() + COMPONENT_IDENTITY_X, header.top() + 18.0),
                    egui::Align2::LEFT_CENTER,
                    view.options.title,
                    TypeRole::Title.font(),
                    TEXT,
                );
                ui.painter().text(
                    egui::pos2(header.left() + COMPONENT_IDENTITY_X, header.top() + 34.0),
                    egui::Align2::LEFT_CENTER,
                    view.options.summary,
                    TypeRole::Small.font(),
                    TEXT_MUTED,
                );
                let actions_rect = egui::Rect::from_min_size(
                    egui::pos2(
                        header.right() - COMPONENT_ACTIONS_WIDTH - 8.0,
                        header.top() + 11.0,
                    ),
                    egui::vec2(COMPONENT_ACTIONS_WIDTH, 28.0),
                );
                ui.scope_builder(egui::UiBuilder::new().max_rect(actions_rect), |ui| {
                    ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
                        actions_menu(ui, view, &mut action);
                        let color = if view.active { SUCCESS } else { TEXT_MUTED };
                        let status_rect = ui
                            .allocate_exact_size(egui::vec2(8.0, 14.0), egui::Sense::hover())
                            .0;
                        ui.painter().circle_filled(status_rect.center(), 4.0, color);
                        ui.label(
                            TypeRole::Small
                                .text(if view.active { "Active" } else { "Off" })
                                .color(TEXT_DIM),
                        );
                    });
                });
                if response.clicked()
                    && ui
                        .input(|input| input.pointer.interact_pos())
                        .is_some_and(|point| {
                            !caret_rect.contains(point) && !actions_rect.contains(point)
                        })
                {
                    action.collapsed = Some(!view.collapsed);
                }
                if !view.collapsed {
                    egui::Frame::new()
                        .inner_margin(egui::Margin {
                            left: view.options.body_margin,
                            right: view.options.body_margin,
                            top: 10,
                            bottom: view.options.body_margin,
                        })
                        .show(ui, add_contents);
                }
            });
    });
    ui.add_space(6.0);
    action
}

fn actions_menu(
    ui: &mut egui::Ui,
    view: &ComponentCardViewModel,
    action: &mut ComponentCardAction,
) {
    ui.menu_button(
        icon_text(icons::DOTS_THREE_VERTICAL, 16.0).color(TEXT_DIM),
        |ui| {
            ui.set_min_width(160.0);
            action.reset |= action_button(ui, view.options.resettable, "Reset");
            action.copy |= action_button(ui, view.options.copyable, "Copy Values");
            action.paste |= action_button(ui, view.pasteable, "Paste Values");
            ui.separator();
            action.move_up |= action_button(ui, view.can_move_up, "Move Up");
            action.move_down |= action_button(ui, view.can_move_down, "Move Down");
            ui.separator();
            ui.add_enabled(false, egui::Button::new("Open Documentation"));
            if ui
                .add_enabled(
                    view.options.removable,
                    egui::Button::new(egui::RichText::new("Remove").color(ERROR)),
                )
                .clicked()
            {
                action.remove = true;
                ui.close();
            }
        },
    );
}

fn action_button(ui: &mut egui::Ui, enabled: bool, label: &str) -> bool {
    let clicked = ui.add_enabled(enabled, egui::Button::new(label)).clicked();
    if clicked {
        ui.close();
    }
    clicked
}

fn icon_text(icon: Icon, size: f32) -> egui::RichText {
    egui::RichText::new(icon.as_str()).font(egui::FontId::new(
        size,
        egui::FontFamily::Name("phosphor-bold".into()),
    ))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn penpot_component_header_geometry_is_exact() {
        assert_eq!(COMPONENT_HEADER_HEIGHT, 50.0);
        assert_eq!(COMPONENT_RAIL_X, 7.0);
        assert_eq!(COMPONENT_CARET_CENTER_X, 26.0);
        assert_eq!(COMPONENT_ICON_CENTER_X, 51.0);
        assert_eq!(COMPONENT_IDENTITY_X, 69.0);
        assert_eq!(COMPONENT_ACTIONS_WIDTH, 104.0);
    }
}
