use crate::ecs::ui::components::UiAnimationPhase;
use crate::ecs::ui::state::{UiBase, UiDisabled, UiFocused, UiHover, UiPressed, UiStateTrait};
use crate::ecs::world::World;

use crate::prelude::*;
pub fn ui_layout_state_update_system(world: &mut World) {
    if !world.resources.retained_ui.enabled {
        return;
    }

    let delta_time = world.resources.window.timing.delta_time;
    let reduced_motion = world.resources.retained_ui.accessibility.reduced_motion;

    let entities: Vec<freecs::Entity> = world
        .ui
        .query_entities(crate::ecs::world::UI_STATE_WEIGHTS)
        .collect();

    let mut any_weight_changed = false;

    for entity in entities {
        let (hover_target, pressed_target, focused_target, disabled_target) = {
            match world.ui.get_ui_node_interaction(entity) {
                Some(interaction) => (
                    if interaction.hovered { 1.0 } else { 0.0 },
                    if interaction.pressed { 1.0 } else { 0.0 },
                    if interaction.focused { 1.0 } else { 0.0 },
                    if interaction.disabled { 1.0 } else { 0.0 },
                ),
                None => (0.0, 0.0, 0.0, 0.0),
            }
        };

        if let Some(state_weights) = world.ui.get_ui_state_weights_mut(entity) {
            let targets = [
                (UiHover::INDEX, hover_target),
                (UiPressed::INDEX, pressed_target),
                (UiFocused::INDEX, focused_target),
                (UiDisabled::INDEX, disabled_target),
            ];

            for (index, target) in targets {
                let previous = state_weights.weights[index];

                if (state_weights.targets[index] - target).abs() > f32::EPSILON {
                    state_weights.targets[index] = target;
                    state_weights.start_weights[index] = previous;
                    state_weights.progress[index] = 0.0;
                }

                if reduced_motion {
                    state_weights.weights[index] = state_weights.targets[index];
                    state_weights.progress[index] = 1.0;
                    state_weights.velocity[index] = 0.0;
                } else {
                    let transition = state_weights.transitions[index].unwrap_or_default();

                    if let Some(spring) = transition.spring {
                        let mass = spring.mass.max(0.0001);
                        let displacement = state_weights.weights[index] - target;
                        let acceleration = (-spring.stiffness * displacement
                            - spring.damping * state_weights.velocity[index])
                            / mass;
                        state_weights.velocity[index] += acceleration * delta_time;
                        state_weights.weights[index] += state_weights.velocity[index] * delta_time;

                        let speed_settled = state_weights.velocity[index].abs() < 0.0005;
                        let position_settled = displacement.abs() < 0.0005;
                        if speed_settled && position_settled {
                            state_weights.weights[index] = target;
                            state_weights.velocity[index] = 0.0;
                            state_weights.progress[index] = 1.0;
                        } else {
                            state_weights.progress[index] = 0.0;
                        }

                        state_weights.weights[index] =
                            state_weights.weights[index].clamp(-0.5, 1.5);
                    } else if state_weights.progress[index] < 1.0 {
                        let speed = if target > state_weights.start_weights[index] {
                            transition.enter_speed
                        } else {
                            transition.exit_speed
                        };

                        state_weights.progress[index] =
                            (state_weights.progress[index] + speed * delta_time).min(1.0);

                        let eased = transition.easing.evaluate(state_weights.progress[index]);
                        let start = state_weights.start_weights[index];
                        state_weights.weights[index] =
                            (start + (target - start) * eased).clamp(0.0, 1.0);
                        state_weights.velocity[index] = 0.0;
                    }
                }

                if (state_weights.weights[index] - previous).abs() > f32::EPSILON {
                    any_weight_changed = true;
                }
            }

            let non_base_sum: f32 = state_weights.weights[1..]
                .iter()
                .map(|w| w.clamp(0.0, 1.0))
                .sum();
            state_weights.weights[UiBase::INDEX] = (1.0 - non_base_sum).clamp(0.0, 1.0);
        }
    }

    if any_weight_changed {
        ui_mark_layout_dirty(world);
    }

    let anim_entities: Vec<freecs::Entity> = world
        .ui
        .query_entities(crate::ecs::world::UI_LAYOUT_NODE)
        .collect();

    for entity in anim_entities {
        let should_hide = if let Some(node) = world.ui.get_ui_layout_node_mut(entity)
            && let Some(animation) = &mut node.animation
        {
            match animation.phase {
                UiAnimationPhase::IntroPlaying => {
                    animation.progress += delta_time / animation.duration;
                    if animation.progress >= 1.0 {
                        animation.progress = 1.0;
                        animation.phase = UiAnimationPhase::Idle;
                    }
                    ui_mark_layout_dirty(world);
                    false
                }
                UiAnimationPhase::OutroPlaying => {
                    animation.progress += delta_time / animation.duration;
                    if animation.progress >= 1.0 {
                        animation.progress = 1.0;
                        animation.phase = UiAnimationPhase::OutroComplete;
                        ui_mark_layout_dirty(world);
                        true
                    } else {
                        ui_mark_layout_dirty(world);
                        false
                    }
                }
                _ => false,
            }
        } else {
            false
        };

        if should_hide && let Some(node) = world.ui.get_ui_layout_node_mut(entity) {
            node.visible = false;
        }
    }

    ui_tick_toasts(world);

    let progress = &mut world.resources.retained_ui.top_progress_bar;
    if progress.is_active() {
        progress.phase = (progress.phase + delta_time).rem_euclid(2.0);
        world.resources.retained_ui.dirty.render_dirty = true;
    }
}
