//! Transform section (authoring) for the actor inspector.

use bevy::prelude::*;
use bevy_egui::egui;
use egui_phosphor_icons::icons;

use crate::history::set_transform_with_history;
use crate::ui::inspector::{
    apply_component_card_response, component_card, component_card_context, ComponentCardOptions,
    COMPONENT_TRANSFORM,
};
use crate::ui::theme::TEXT_DIM;

const WIDE_TRANSFORM_ROW_WIDTH: f32 = 360.0;
const TRANSFORM_LABEL_WIDTH: f32 = 124.0;
const AXIS_FIELD_WIDTH: f32 = 76.0;

pub fn transform_inspector_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
    let Some(mut transform) = world.get::<Transform>(entity).cloned() else {
        return;
    };
    let old = transform;
    let mut changed = false;

    let card = component_card_context(
        world,
        entity,
        ComponentCardOptions::fixed(COMPONENT_TRANSFORM, "Transform", icons::ARROWS_OUT_CARDINAL),
    );
    let card_response = component_card(ui, &card, |ui| {
        if transform_row(ui, "Position", &mut transform.translation, 0.1) {
            changed = true;
        }

        let (yaw, pitch, roll) = transform.rotation.to_euler(EulerRot::YXZ);
        let mut rotation_deg = Vec3::new(pitch.to_degrees(), yaw.to_degrees(), roll.to_degrees());
        if transform_row(ui, "Rotation (degrees)", &mut rotation_deg, 0.5) {
            transform.rotation = Quat::from_euler(
                EulerRot::YXZ,
                rotation_deg.y.to_radians(),
                rotation_deg.x.to_radians(),
                rotation_deg.z.to_radians(),
            );
            changed = true;
        }

        if transform_row(ui, "Scale", &mut transform.scale, 0.05) {
            changed = true;
        }
    });

    let reset = card_response.reset;
    apply_component_card_response(world, entity, card_response);

    if reset {
        set_transform_with_history(world, entity, old, Transform::default());
    } else if changed {
        set_transform_with_history(world, entity, old, transform);
    }
}

fn transform_row(ui: &mut egui::Ui, label: &str, value: &mut Vec3, speed: f64) -> bool {
    let mut changed = false;
    if ui.available_width() < WIDE_TRANSFORM_ROW_WIDTH {
        ui.vertical(|ui| {
            ui.label(label);
            ui.horizontal_wrapped(|ui| {
                changed |= axis_drag(ui, "X", &mut value.x, speed);
                changed |= axis_drag(ui, "Y", &mut value.y, speed);
                changed |= axis_drag(ui, "Z", &mut value.z, speed);
            });
        });
    } else {
        ui.horizontal(|ui| {
            ui.add_sized(
                [TRANSFORM_LABEL_WIDTH.min(ui.available_width()), 20.0],
                egui::Label::new(label),
            );
            changed |= axis_drag(ui, "X", &mut value.x, speed);
            changed |= axis_drag(ui, "Y", &mut value.y, speed);
            changed |= axis_drag(ui, "Z", &mut value.z, speed);
        });
    }
    changed
}

fn axis_drag(ui: &mut egui::Ui, axis: &str, value: &mut f32, speed: f64) -> bool {
    ui.horizontal(|ui| {
        ui.label(egui::RichText::new(axis).color(axis_color(axis)).strong());
        ui.add_sized(
            [AXIS_FIELD_WIDTH.min(ui.available_width().max(44.0)), 20.0],
            egui::DragValue::new(value)
                .speed(speed)
                .max_decimals(3)
                .min_decimals(1),
        )
        .changed()
    })
    .inner
}

fn axis_color(axis: &str) -> egui::Color32 {
    match axis {
        "X" => egui::Color32::from_rgb(229, 82, 73),
        "Y" => egui::Color32::from_rgb(103, 190, 92),
        "Z" => egui::Color32::from_rgb(88, 132, 241),
        _ => TEXT_DIM,
    }
}
