//! Static/skinned renderer-array presentation shared by production and the UI gallery.

use egui;
use egui_phosphor_icons::icons;

use crate::design_system;
use crate::design_system::typography::TypeRole;
use crate::theme::{BORDER, PANEL_BG_DARK, WIDGET_BG};

pub const RENDERER_ARRAY_HEADER_HEIGHT: f32 = 40.0;
pub const EXPANDED_RENDERER_HEADER_HEIGHT: f32 = 84.0;
pub const COLLAPSED_RENDERER_HEADER_HEIGHT: f32 = 60.0;
pub const RENDERER_PROPERTIES_HEADER_HEIGHT: f32 = 38.0;
pub const MATERIAL_SLOTS_HEADER_HEIGHT: f32 = 50.0;

#[derive(Clone, Copy)]
pub struct RendererPanelHeaderViewModel<'a> {
    pub index: usize,
    pub label: &'a str,
    pub path: &'a str,
    pub slot_count: usize,
    pub texture_id: Option<egui::TextureId>,
}

pub fn renderer_array_header(ui: &mut egui::Ui, count: usize) -> bool {
    let palette = design_system::palette(ui);
    let (rect, _) = ui.allocate_exact_size(
        egui::vec2(ui.available_width().max(1.0), RENDERER_ARRAY_HEADER_HEIGHT),
        egui::Sense::hover(),
    );
    ui.painter().rect_filled(rect, 4.0, palette.elevated);
    ui.painter().text(
        rect.left_center() + egui::vec2(12.0, 0.0),
        egui::Align2::LEFT_CENTER,
        icons::SQUARES_FOUR.as_str(),
        egui::FontId::new(16.0, egui::FontFamily::Name("phosphor-regular".into())),
        palette.text_secondary,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(32.0, 0.0),
        egui::Align2::LEFT_CENTER,
        "Mesh renderers",
        TypeRole::Section.font(),
        palette.text_primary,
    );
    let badge = egui::Rect::from_center_size(
        rect.left_center() + egui::vec2(124.0, 0.0),
        egui::vec2(20.0, 20.0),
    );
    ui.painter()
        .circle_filled(badge.center(), 10.0, palette.accent.linear_multiply(0.22));
    ui.painter().text(
        badge.center(),
        egui::Align2::CENTER_CENTER,
        format!("{count}"),
        TypeRole::Small.font(),
        palette.accent,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(144.0, 0.0),
        egui::Align2::LEFT_CENTER,
        "Each renderer owns the slots exposed by its mesh",
        TypeRole::Caption.font(),
        palette.text_muted,
    );
    let add_rect = egui::Rect::from_min_size(
        egui::pos2(rect.right() - 116.0, rect.top() + 7.0),
        egui::vec2(104.0, 26.0),
    );
    ui.put(
        add_rect,
        egui::Button::new(design_system::controls::icon_label(
            icons::PLUS,
            "Add renderer",
            TypeRole::Body,
            12.0,
            palette.text_primary,
        )),
    )
    .clicked()
}

pub fn renderer_panel(ui: &mut egui::Ui, add_contents: impl FnOnce(&mut egui::Ui)) {
    egui::Frame::new()
        .fill(WIDGET_BG.linear_multiply(0.82))
        .stroke(egui::Stroke::new(1.0_f32, BORDER))
        .corner_radius(egui::CornerRadius::same(5))
        .show(ui, |ui| {
            ui.set_max_width(ui.available_width());
            add_contents(ui);
        });
    ui.add_space(10.0);
}

pub fn renderer_panel_header(
    ui: &mut egui::Ui,
    model: RendererPanelHeaderViewModel<'_>,
    open: &mut bool,
    add_actions: impl FnOnce(&mut egui::Ui),
) {
    let palette = design_system::palette(ui);
    let height = if *open {
        EXPANDED_RENDERER_HEADER_HEIGHT
    } else {
        COLLAPSED_RENDERER_HEADER_HEIGHT
    };
    let (rect, header_response) = ui.allocate_exact_size(
        egui::vec2(ui.available_width().max(1.0), height),
        egui::Sense::click(),
    );
    ui.painter().rect_filled(
        egui::Rect::from_min_size(
            rect.min + egui::vec2(6.0, 8.0),
            egui::vec2(3.0, height - 16.0),
        ),
        2.0,
        palette.accent,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(24.0, 0.0),
        egui::Align2::CENTER_CENTER,
        if *open {
            icons::CARET_DOWN.as_str()
        } else {
            icons::CARET_RIGHT.as_str()
        },
        egui::FontId::new(12.0, egui::FontFamily::Name("phosphor-regular".into())),
        palette.text_secondary,
    );
    let preview_size = if *open { 58.0 } else { 40.0 };
    let preview = egui::Rect::from_center_size(
        egui::pos2(rect.left() + 68.0, rect.center().y),
        egui::vec2(preview_size, preview_size),
    );
    ui.painter().rect(
        preview,
        4.0,
        PANEL_BG_DARK,
        egui::Stroke::new(1.0_f32, BORDER),
        egui::StrokeKind::Inside,
    );
    if let Some(texture_id) = model.texture_id {
        ui.painter().image(
            texture_id,
            preview.shrink(3.0),
            egui::Rect::from_min_max(egui::Pos2::ZERO, egui::pos2(1.0, 1.0)),
            egui::Color32::WHITE,
        );
    } else {
        ui.painter().text(
            preview.center(),
            egui::Align2::CENTER_CENTER,
            icons::CUBE.as_str(),
            egui::FontId::new(20.0, egui::FontFamily::Name("phosphor-bold".into())),
            palette.text_secondary,
        );
    }
    let label = if model.label.trim().is_empty() {
        "Mesh renderer"
    } else {
        model.label.trim()
    };
    let identity_x = rect.left() + 105.0;
    if *open {
        ui.painter().text(
            egui::pos2(identity_x, rect.top() + 28.0),
            egui::Align2::LEFT_CENTER,
            format!("RENDERER {}", model.index),
            TypeRole::Eyebrow.font(),
            palette.accent,
        );
    }
    ui.painter().text(
        egui::pos2(
            identity_x,
            if *open {
                rect.top() + 45.0
            } else {
                rect.center().y - 7.0
            },
        ),
        egui::Align2::LEFT_CENTER,
        label,
        TypeRole::AssetTitle.font(),
        palette.text_primary,
    );
    ui.painter().text(
        egui::pos2(
            identity_x,
            if *open {
                rect.top() + 62.0
            } else {
                rect.center().y + 9.0
            },
        ),
        egui::Align2::LEFT_CENTER,
        if *open {
            model.path.to_owned()
        } else {
            format!(
                "Renderer {} · {} material slot{}",
                model.index,
                model.slot_count,
                if model.slot_count == 1 { "" } else { "s" }
            )
        },
        TypeRole::Small.font(),
        palette.text_muted,
    );
    let slot_badge = egui::Rect::from_min_size(
        egui::pos2(
            rect.right() - if *open { 60.0 } else { 78.0 },
            rect.top() + if *open { 12.0 } else { 8.0 },
        ),
        egui::vec2(40.0, 20.0),
    );
    ui.painter()
        .rect_filled(slot_badge, 10.0, palette.accent.linear_multiply(0.22));
    ui.painter().text(
        slot_badge.center(),
        egui::Align2::CENTER_CENTER,
        format!(
            "{} slot{}",
            model.slot_count,
            if model.slot_count == 1 { "" } else { "s" }
        ),
        TypeRole::Eyebrow.font(),
        palette.accent,
    );
    let action_rect = if *open {
        ui.painter().circle_filled(
            egui::pos2(rect.right() - 10.0, rect.top() + 22.0),
            4.0,
            palette.healthy,
        );
        let action_rect = egui::Rect::from_min_size(
            egui::pos2(rect.right() - 132.0, rect.bottom() - 38.0),
            egui::vec2(122.0, 28.0),
        );
        ui.scope_builder(egui::UiBuilder::new().max_rect(action_rect), |ui| {
            ui.with_layout(
                egui::Layout::right_to_left(egui::Align::Center),
                add_actions,
            );
        });
        action_rect
    } else {
        let action_rect = egui::Rect::from_center_size(
            egui::pos2(rect.right() - 20.0, rect.center().y),
            egui::vec2(28.0, 28.0),
        );
        ui.scope_builder(egui::UiBuilder::new().max_rect(action_rect), |ui| {
            design_system::controls::icon_button(
                ui,
                icons::DOTS_THREE_VERTICAL,
                "Renderer actions",
                true,
            );
        });
        action_rect
    };
    if header_response.clicked()
        && ui
            .input(|input| input.pointer.interact_pos())
            .is_some_and(|pointer| !preview.contains(pointer) && !action_rect.contains(pointer))
    {
        *open = !*open;
    }
}

pub fn renderer_material_slots_header(ui: &mut egui::Ui, count: usize) {
    let palette = design_system::palette(ui);
    let (rect, _) = ui.allocate_exact_size(
        egui::vec2(ui.available_width().max(1.0), MATERIAL_SLOTS_HEADER_HEIGHT),
        egui::Sense::hover(),
    );
    ui.painter().rect_filled(rect, 0.0, palette.elevated);
    ui.painter().text(
        rect.left_center() + egui::vec2(15.0, 0.0),
        egui::Align2::CENTER_CENTER,
        icons::CARET_DOWN.as_str(),
        egui::FontId::new(10.0, egui::FontFamily::Name("phosphor-bold".into())),
        palette.text_secondary,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(35.0, 0.0),
        egui::Align2::CENTER_CENTER,
        icons::PALETTE.as_str(),
        egui::FontId::new(14.0, egui::FontFamily::Name("phosphor-bold".into())),
        palette.accent,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(49.0, 0.0),
        egui::Align2::LEFT_CENTER,
        "Material slots",
        TypeRole::Section.font(),
        palette.text_primary,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(122.0, 0.0),
        egui::Align2::LEFT_CENTER,
        format!("{count} exposed by mesh"),
        TypeRole::Caption.font(),
        palette.text_muted,
    );
    ui.painter().line_segment(
        [
            egui::pos2(rect.left() + 201.0, rect.center().y),
            egui::pos2(rect.right() - 93.0, rect.center().y),
        ],
        egui::Stroke::new(1.0_f32, palette.border),
    );
    ui.painter().text(
        rect.right_center() - egui::vec2(76.0, 0.0),
        egui::Align2::CENTER_CENTER,
        icons::LINK.as_str(),
        egui::FontId::new(12.0, egui::FontFamily::Name("phosphor-bold".into())),
        palette.text_muted,
    );
    ui.painter().text(
        rect.right_center() - egui::vec2(10.0, 0.0),
        egui::Align2::RIGHT_CENTER,
        "Index mapped",
        TypeRole::Eyebrow.font(),
        palette.text_muted,
    );
}

pub fn renderer_properties_header(ui: &mut egui::Ui) {
    let palette = design_system::palette(ui);
    let (rect, _) = ui.allocate_exact_size(
        egui::vec2(
            ui.available_width().max(1.0),
            RENDERER_PROPERTIES_HEADER_HEIGHT,
        ),
        egui::Sense::hover(),
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(4.0, 0.0),
        egui::Align2::CENTER_CENTER,
        icons::SLIDERS_HORIZONTAL.as_str(),
        egui::FontId::new(13.0, egui::FontFamily::Name("phosphor-bold".into())),
        palette.accent,
    );
    ui.painter().text(
        rect.left_center() + egui::vec2(20.0, 0.0),
        egui::Align2::LEFT_CENTER,
        "Renderer properties",
        TypeRole::AssetLabel.font(),
        palette.accent,
    );
    ui.painter().text(
        rect.right_center(),
        egui::Align2::RIGHT_CENTER,
        "Mesh + render flags",
        TypeRole::Caption.font(),
        palette.text_muted,
    );
}

pub fn renderer_material_slot_row<R>(
    ui: &mut egui::Ui,
    index: usize,
    add_contents: impl FnOnce(&mut egui::Ui) -> R,
) -> R {
    let palette = design_system::palette(ui);
    let row = ui.horizontal_top(|ui| {
        let (index_rect, _) = ui.allocate_exact_size(egui::vec2(39.0, 60.0), egui::Sense::hover());
        ui.painter().text(
            index_rect.center_top() + egui::vec2(0.0, 8.0),
            egui::Align2::CENTER_CENTER,
            "SLOT",
            TypeRole::Caption.font(),
            palette.text_muted,
        );
        ui.painter().text(
            index_rect.center_top() + egui::vec2(0.0, 18.0),
            egui::Align2::CENTER_CENTER,
            index.to_string(),
            TypeRole::Body.font(),
            palette.text_muted,
        );
        ui.vertical(|ui| {
            ui.set_width(ui.available_width().max(1.0));
            add_contents(ui)
        })
        .inner
    });
    let rail_x = row.response.rect.left() + 23.0;
    ui.painter().line_segment(
        [
            egui::pos2(rail_x, row.response.rect.top() + 35.0),
            egui::pos2(rail_x, row.response.rect.bottom() - 8.0),
        ],
        egui::Stroke::new(1.0_f32, palette.border_strong),
    );
    row.inner
}

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

    #[test]
    fn renderer_headers_match_current_penpot_heights() {
        assert_eq!(RENDERER_ARRAY_HEADER_HEIGHT, 40.0);
        assert_eq!(EXPANDED_RENDERER_HEADER_HEIGHT, 84.0);
        assert_eq!(COLLAPSED_RENDERER_HEADER_HEIGHT, 60.0);
        assert_eq!(RENDERER_PROPERTIES_HEADER_HEIGHT, 38.0);
        assert_eq!(MATERIAL_SLOTS_HEADER_HEIGHT, 50.0);
    }
}
