use crate::{
    GameState,
    camera::{CameraState, MainCamera},
    global_observer,
    tb_entities::{CameraTarget, CutsceneCamera, CutsceneCameraMovementEnd},
};
use bevy::prelude::*;
use bevy_trenchbroom::prelude::*;

#[derive(Event, Debug)]
pub struct StartCutscene(pub String);

#[derive(Resource, Debug, Default)]
enum CutsceneState {
    #[default]
    None,
    Playing {
        timer: Timer,
        camera_start: Transform,
        camera_end: Transform,
    },
}

pub fn plugin(app: &mut App) {
    app.init_resource::<CutsceneState>();
    app.add_systems(Update, update.run_if(in_state(GameState::Playing)));

    global_observer!(app, on_start_cutscene);
}

fn on_start_cutscene(
    trigger: Trigger<StartCutscene>,
    mut cam_state: ResMut<CameraState>,
    mut cutscene_state: ResMut<CutsceneState>,
    cutscenes: Query<(&Transform, &CutsceneCamera, &Target), Without<MainCamera>>,
    cutscene_movement: Query<
        (&Transform, &CutsceneCameraMovementEnd, &Target),
        Without<MainCamera>,
    >,
    cam_target: Query<(&Transform, &CameraTarget), Without<MainCamera>>,
) {
    let cutscene = trigger.event().0.clone();

    cam_state.cutscene = true;

    // asumes `name` and `targetname` are equal
    let Some((t, _, target)) = cutscenes
        .iter()
        .find(|(_, cutscene_camera, _)| cutscene == cutscene_camera.name)
    else {
        return;
    };

    let move_end = cutscene_movement
        .iter()
        .find(|(_, _, target)| cutscene == target.target.clone().unwrap_or_default())
        .map(|(t, _, _)| *t)
        .unwrap_or_else(|| *t);

    let Some((target, _)) = cam_target.iter().find(|(_, camera_target)| {
        camera_target.targetname == target.target.clone().unwrap_or_default()
    }) else {
        return;
    };

    *cutscene_state = CutsceneState::Playing {
        timer: Timer::from_seconds(2.0, TimerMode::Once),
        camera_start: t.looking_at(target.translation, Vec3::Y),
        camera_end: move_end.looking_at(target.translation, Vec3::Y),
    };
}

fn update(
    mut cam_state: ResMut<CameraState>,
    mut cutscene_state: ResMut<CutsceneState>,
    mut cam: Query<&mut Transform, With<MainCamera>>,
    time: Res<Time>,
) {
    if let CutsceneState::Playing {
        timer,
        camera_start,
        camera_end,
    } = &mut *cutscene_state
    {
        cam_state.cutscene = true;
        timer.tick(time.delta());

        let t = Transform::from_translation(
            camera_start
                .translation
                .lerp(camera_end.translation, timer.fraction()),
        )
        .with_rotation(
            camera_start
                .rotation
                .lerp(camera_end.rotation, timer.fraction()),
        );

        let _ = cam.single_mut().map(|mut cam| *cam = t);

        if timer.finished() {
            cam_state.cutscene = false;
            *cutscene_state = CutsceneState::None;
        }
    }
}
