use crate::{
    GameState, global_observer,
    tb_entities::{Movable, MoveTarget},
};
use bevy::{platform::collections::HashSet, prelude::*};
use bevy_trenchbroom::prelude::*;

#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
struct ActiveMovable {
    pub start: Transform,
    pub target: Transform,
    pub start_time: f32,
    pub duration: f32,
}

#[derive(Event)]
pub struct TriggerMovableEvent(pub HashSet<String>);

pub fn plugin(app: &mut App) {
    app.register_type::<ActiveMovable>();
    app.add_systems(Update, move_active.run_if(in_state(GameState::Playing)));

    global_observer!(app, on_movable_event);
}

fn on_movable_event(
    trigger: Trigger<TriggerMovableEvent>,
    mut commands: Commands,
    uninit_movables: Query<
        (Entity, &Target, &Transform, &Movable),
        (Without<ActiveMovable>, With<Movable>),
    >,
    targets: Query<(&MoveTarget, &Transform)>,
    time: Res<Time>,
) {
    info!("trigger: {:?}", trigger.0);

    for (e, target, transform, movable) in uninit_movables.iter() {
        if !trigger.0.contains(&movable.name) {
            continue;
        }

        let target_name = target.target.clone().unwrap_or_default();

        let Some(target) = targets
            .iter()
            .find(|(t, _)| t.targetname == target_name)
            .map(|(_, t)| *t)
        else {
            continue;
        };

        info!("found target: {:?}", target_name);

        let target: Transform =
            Transform::from_translation(transform.translation).with_rotation(target.rotation);

        let platform = ActiveMovable {
            start: *transform,
            target,
            start_time: time.elapsed_secs(),
            //TODO: make this configurable
            duration: 2.,
        };

        commands.entity(e).insert(platform);
    }
}

fn move_active(
    mut commands: Commands,
    mut platforms: Query<(Entity, &mut Transform, &mut ActiveMovable)>,
    time: Res<Time>,
) {
    let elapsed = time.elapsed_secs();
    for (e, mut transform, active) in platforms.iter_mut() {
        if elapsed < active.start_time + active.duration {
            let t = (elapsed - active.start_time) / active.duration;
            transform.rotation = active.start.rotation.lerp(active.target.rotation, t);
        } else {
            *transform = active.target;
            commands.entity(e).remove::<(ActiveMovable, Movable)>();
        }
    }
}
