//! Shared material UV-transform authoring used by Materials and Material Instances.

use bevy::prelude::Vec2;
use bevy_egui::egui;
use egui_phosphor_icons::icons;
use shared::{MaterialInputSet, MaterialParameter, MaterialParameterValue};

use crate::ui::design_system;
use crate::ui::design_system::typography::TypeRole;

pub(super) fn uv_transform_section(
    ui: &mut egui::Ui,
    offset: &mut Vec2,
    tiling: &mut Vec2,
    reset_offset: Vec2,
    reset_tiling: Vec2,
) {
    let palette = design_system::palette(ui);
    let width = ui.available_width().max(1.0);
    let height = match super::layout::ResponsiveMaterialLayout::for_width(width) {
        super::layout::ResponsiveMaterialLayout::Reference => {
            crate::ui::design_system::UV_SECTION_HEIGHT
        }
        super::layout::ResponsiveMaterialLayout::Compact => {
            crate::ui::design_system::COMPACT_UV_SECTION_HEIGHT
        }
        super::layout::ResponsiveMaterialLayout::Transient => 100.0,
    };
    let (rect, _) = ui.allocate_exact_size(egui::vec2(width, height), egui::Sense::hover());
    ui.painter().rect(
        rect,
        5.0,
        palette.section,
        egui::Stroke::new(1.0_f32, palette.border),
        egui::StrokeKind::Inside,
    );
    let mut child = ui.new_child(egui::UiBuilder::new().max_rect(rect));
    child.set_clip_rect(rect.intersect(ui.clip_rect()));
    let geometry = super::layout::UvSectionGeometry::for_rect(rect);
    child.painter().text(
        geometry.title.left_center(),
        egui::Align2::LEFT_CENTER,
        "UV",
        TypeRole::Section.font(),
        palette.text_primary,
    );
    vec2_group(
        &mut child,
        geometry.offset,
        "Offset",
        offset,
        reset_offset,
        "Reset UV offset",
    );
    vec2_group(
        &mut child,
        geometry.tiling,
        "Tiling",
        tiling,
        reset_tiling,
        "Reset UV tiling",
    );
}

fn vec2_group(
    ui: &mut egui::Ui,
    geometry: super::layout::UvGroupGeometry,
    label: &str,
    value: &mut Vec2,
    reset: Vec2,
    tooltip: &str,
) {
    let palette = design_system::palette(ui);
    ui.painter().text(
        geometry.label.left_center(),
        egui::Align2::LEFT_CENTER,
        label,
        TypeRole::Small.font(),
        palette.text_muted,
    );
    ui.put(
        geometry.x,
        egui::DragValue::new(&mut value.x).speed(0.01).prefix("X "),
    );
    ui.put(
        geometry.y,
        egui::DragValue::new(&mut value.y).speed(0.01).prefix("Y "),
    );
    if let Some(reset_rect) = geometry.reset {
        let enabled = *value != reset;
        let response = ui.put(
            reset_rect,
            egui::Button::new(
                egui::RichText::new(icons::ARROW_COUNTER_CLOCKWISE.as_str()).font(
                    egui::FontId::new(14.0, egui::FontFamily::Name("phosphor-bold".into())),
                ),
            ),
        );
        if enabled && response.clicked() {
            *value = reset;
        }
        response.on_hover_text(tooltip);
    }
}

pub(super) fn material_vec2_value(inputs: &MaterialInputSet, name: &str, default: Vec2) -> Vec2 {
    inputs
        .values
        .iter()
        .find(|parameter| parameter.name == name)
        .and_then(|parameter| match parameter.value {
            MaterialParameterValue::Vec2(value) => Some(value),
            _ => None,
        })
        .unwrap_or(default)
}

pub(super) fn set_material_vec2_value(inputs: &mut MaterialInputSet, name: &str, value: Vec2) {
    if let Some(parameter) = inputs
        .values
        .iter_mut()
        .find(|parameter| parameter.name == name)
    {
        parameter.value = MaterialParameterValue::Vec2(value);
    } else {
        inputs.values.push(MaterialParameter {
            name: name.into(),
            value: MaterialParameterValue::Vec2(value),
        });
    }
}
