use crate::ecs::ui::state::UiStateTrait as _;
use crate::ecs::world::World;
use nalgebra_glm::Vec2;

use super::InteractionSnapshot;

pub(super) fn handle_toggle(
    world: &mut World,
    entity: freecs::Entity,
    interaction: &InteractionSnapshot,
    data: &crate::ecs::ui::components::UiToggleData,
    delta_time: f32,
) {
    let mut value = data.value;
    let mut changed = false;
    let mut animated_position = data.animated_position;

    if interaction.clicked {
        value = !value;
        changed = true;
    }

    let target = if value { 1.0 } else { 0.0 };
    let speed = 8.0;
    let diff = target - animated_position;
    if diff.abs() > 0.001 {
        animated_position += diff.signum() * speed * delta_time;
        animated_position = animated_position.clamp(0.0, 1.0);
    } else {
        animated_position = target;
    }

    let theme = world.resources.retained_ui.theme_state.active_theme();
    let toggle_height = theme.toggle_height;
    let toggle_width = theme.toggle_width;
    let on_color = theme.accent_color;
    let off_color = theme.background_color;
    let knob_padding = 2.0;
    let knob_size = toggle_height - knob_padding * 2.0;
    let knob_travel = toggle_width - knob_size - knob_padding * 2.0;
    let knob_x = knob_padding + animated_position * knob_travel;
    if let Some(knob_node) = world.ui.get_ui_layout_node_mut(data.knob_entity)
        && let Some(crate::ecs::ui::layout_types::UiLayoutType::Window(window)) =
            knob_node.base_layout.as_mut()
    {
        window.position = crate::ecs::ui::units::Ab(Vec2::new(knob_x, knob_padding)).into();
    }
    let blended = off_color + (on_color - off_color) * animated_position;
    if let Some(color) = world.ui.get_ui_node_color_mut(entity) {
        color.colors[crate::ecs::ui::state::UiBase::INDEX] = Some(blended);
    }

    if let Some(widget_data) = world.ui.get_ui_toggle_mut(entity) {
        widget_data.value = value;
        widget_data.changed = changed;
        widget_data.animated_position = animated_position;
    }
    if changed {
        world
            .resources
            .retained_ui
            .frame
            .events
            .push(crate::ecs::ui::resources::UiEvent::ToggleChanged { entity, value });
    }
}

pub(super) fn handle_checkbox(
    world: &mut World,
    entity: freecs::Entity,
    interaction: &InteractionSnapshot,
    data: &crate::ecs::ui::components::UiCheckboxData,
) {
    if interaction.clicked {
        let new_value = !data.value;
        if let Some(node) = world.ui.get_ui_layout_node_mut(data.inner_entity) {
            node.visible = new_value;
        }
        if let Some(widget_data) = world.ui.get_ui_checkbox_mut(entity) {
            widget_data.value = new_value;
            widget_data.changed = true;
        }
        world.resources.retained_ui.events_for_active_mut().push(
            crate::ecs::ui::resources::UiEvent::CheckboxChanged {
                entity,
                value: new_value,
            },
        );
    } else if let Some(widget_data) = world.ui.get_ui_checkbox_mut(entity) {
        widget_data.changed = false;
    }
}

pub(super) fn handle_radio(
    world: &mut World,
    entity: freecs::Entity,
    interaction: &InteractionSnapshot,
    data: &crate::ecs::ui::components::UiRadioData,
) {
    if let Some(widget_data) = world.ui.get_ui_radio_mut(entity) {
        widget_data.changed = false;
    }

    if interaction.clicked && !data.selected {
        if let Some(node) = world.ui.get_ui_layout_node_mut(data.inner_entity) {
            node.visible = true;
        }

        let siblings = world
            .resources
            .retained_ui
            .groups
            .radio
            .get(&data.group_id)
            .cloned()
            .unwrap_or_default();

        for other_entity in siblings {
            if other_entity == entity {
                continue;
            }
            let other_data_clone = world.ui.get_ui_radio(other_entity).cloned();
            if let Some(other_radio) = other_data_clone
                && other_radio.selected
            {
                if let Some(node) = world.ui.get_ui_layout_node_mut(other_radio.inner_entity) {
                    node.visible = false;
                }
                if let Some(widget_data) = world.ui.get_ui_radio_mut(other_entity) {
                    widget_data.selected = false;
                }
            }
        }

        if let Some(widget_data) = world.ui.get_ui_radio_mut(entity) {
            widget_data.selected = true;
            widget_data.changed = true;
        }
        world.resources.retained_ui.events_for_active_mut().push(
            crate::ecs::ui::resources::UiEvent::RadioChanged {
                entity,
                group_id: data.group_id,
                option_index: data.option_index,
            },
        );
    }
}

pub(super) fn handle_collapsing_header(
    world: &mut World,
    entity: freecs::Entity,
    interaction: &InteractionSnapshot,
    data: &crate::ecs::ui::components::UiCollapsingHeaderData,
) {
    if let Some(widget_data) = world.ui.get_ui_collapsing_header_mut(entity) {
        widget_data.changed = false;
    }
    if interaction.clicked {
        let new_open = !data.open;
        if let Some(node) = world.ui.get_ui_layout_node_mut(data.content_entity) {
            node.visible = new_open;
        }
        world.resources.text.cache.set_text(
            data.arrow_text_slot,
            if new_open { "\u{25BC}" } else { "\u{25B6}" },
        );
        if let Some(widget_data) = world.ui.get_ui_collapsing_header_mut(entity) {
            widget_data.open = new_open;
            widget_data.changed = true;
        }
    }
}

pub(super) fn handle_spinner(
    world: &mut World,
    entity: freecs::Entity,
    data: &crate::ecs::ui::components::UiSpinnerData,
    delta_time: f32,
) {
    if data.dots.is_empty() {
        return;
    }
    let dot_count = data.dots.len() as f32;
    let phase = (data.phase + delta_time * data.rotation_speed).rem_euclid(dot_count);
    let accent = world
        .resources
        .retained_ui
        .theme_state
        .active_theme()
        .accent_color;
    let head = phase;
    for (index, dot) in data.dots.iter().enumerate() {
        let offset = (head - index as f32).rem_euclid(dot_count);
        let normalized = offset / dot_count;
        let alpha = 0.18 + (1.0 - normalized) * 0.82;
        if let Some(color) = world.ui.get_ui_node_color_mut(*dot) {
            color.colors[crate::ecs::ui::state::UiBase::INDEX] = Some(nalgebra_glm::Vec4::new(
                accent.x,
                accent.y,
                accent.z,
                alpha * accent.w,
            ));
        }
    }
    if let Some(widget_data) = world.ui.get_ui_spinner_mut(entity) {
        widget_data.phase = phase;
    }
    world.resources.retained_ui.dirty.render_dirty = true;
}
