use crate::ecs::EditorWorld;
use crate::systems::retained_ui::UiHandles;
use nightshade::prelude::*;

const PANEL_RECT: Rect = Rect {
    min: Vec2::new(60.0, 60.0),
    max: Vec2::new(280.0, 280.0),
};

#[derive(Default, Clone, Copy)]
pub struct SnapSettingsHandles {
    pub panel: Entity,
    pub translation_drag: Entity,
    pub rotation_drag: Entity,
    pub scale_drag: Entity,
}

pub fn build(tree: &mut UiTreeBuilder) -> SnapSettingsHandles {
    let panel = tree.add_floating_panel("snap_settings", "Snap settings", PANEL_RECT);
    ui_set_visible(tree.world_mut(), panel, false);
    let content = super::panel_content(tree, panel);

    let mut translation_drag = Entity::default();
    let mut rotation_drag = Entity::default();
    let mut scale_drag = Entity::default();

    tree.in_parent(content, |tree| {
        let grid = tree.add_property_grid(120.0);
        let section = tree.add_property_section(grid, "Steps");

        translation_drag = property_drag(tree, grid, section, "Translate", 0.5, 0.05, 3);
        rotation_drag = property_drag(tree, grid, section, "Rotate (\u{00b0})", 15.0, 0.5, 2);
        scale_drag = property_drag(tree, grid, section, "Scale", 0.1, 0.01, 3);
    });

    SnapSettingsHandles {
        panel,
        translation_drag,
        rotation_drag,
        scale_drag,
    }
}

fn property_drag(
    tree: &mut UiTreeBuilder,
    grid: Entity,
    section: Entity,
    label: &str,
    initial: f32,
    speed: f32,
    precision: usize,
) -> Entity {
    let row = tree.add_property_row(grid, section, label);
    let mut widget = Entity::default();
    tree.in_parent(row, |tree| {
        widget = tree.add_drag_value_configured(
            DragValueConfig::new(0.0, f32::MAX, initial)
                .speed(speed)
                .precision(precision),
        );
    });
    widget
}

pub fn poll(editor_world: &mut EditorWorld, world: &mut World, handles: &UiHandles) {
    let snap_handles = handles.snap_settings;
    for event in ui_events(world) {
        if let UiEvent::DragValueChanged { entity, value } = event {
            let snap = &mut editor_world.resources.snap;
            if *entity == snap_handles.translation_drag {
                snap.translation_step = value.max(0.0);
            } else if *entity == snap_handles.rotation_drag {
                snap.rotation_step_degrees = value.max(0.0);
            } else if *entity == snap_handles.scale_drag {
                snap.scale_step = value.max(0.0);
            }
        }
    }
}

pub fn sync(editor_world: &EditorWorld, world: &mut World) {
    let handles = editor_world.resources.ui_handles.snap_settings;
    let snap = &editor_world.resources.snap;
    sync_drag_value(world, handles.translation_drag, snap.translation_step);
    sync_drag_value(world, handles.rotation_drag, snap.rotation_step_degrees);
    sync_drag_value(world, handles.scale_drag, snap.scale_step);
}

fn sync_drag_value(world: &mut World, entity: Entity, value: f32) {
    if let Some(data) = world.ui.get_ui_drag_value_mut(entity)
        && !data.editing
        && (data.value - value).abs() > f32::EPSILON
    {
        data.value = value;
    }
}
