use crate::camera::MainCamera;
use bevy::prelude::*;
use bevy_sprite3d::Sprite3dPlugin;

#[derive(Component, Reflect, Default, PartialEq, Eq)]
#[reflect(Component)]
pub enum Billboard {
    #[default]
    All,
    XZ,
}

pub fn plugin(app: &mut App) {
    if !app.is_plugin_added::<Sprite3dPlugin>() {
        app.add_plugins(Sprite3dPlugin);
    }

    app.register_type::<Billboard>();
    app.add_systems(Update, (face_camera, face_camera_no_parent));
}

fn face_camera(
    cam_query: Query<&GlobalTransform, With<MainCamera>>,
    mut query: Query<
        (&mut Transform, &ChildOf, &InheritedVisibility, &Billboard),
        Without<MainCamera>,
    >,
    parent_transform: Query<&GlobalTransform>,
) {
    let Ok(cam_transform) = cam_query.single() else {
        return;
    };

    for (mut transform, parent, visible, billboard) in query.iter_mut() {
        if !matches!(*visible, InheritedVisibility::VISIBLE) {
            continue;
        }

        let Ok(parent_global) = parent_transform.get(parent.parent()) else {
            continue;
        };

        let target = cam_transform.reparented_to(parent_global);

        let target = match *billboard {
            Billboard::All => target.translation,
            Billboard::XZ => Vec3::new(
                target.translation.x,
                transform.translation.y,
                target.translation.z,
            ),
        };

        transform.look_at(target, Vec3::Y);
    }
}

fn face_camera_no_parent(
    cam_query: Query<&GlobalTransform, With<MainCamera>>,
    mut query: Query<(&mut Transform, &Billboard), (Without<MainCamera>, Without<ChildOf>)>,
) {
    let Ok(cam_transform) = cam_query.single() else {
        return;
    };
    for (mut transform, billboard) in query.iter_mut() {
        let target = cam_transform.translation();
        let target = match *billboard {
            Billboard::All => cam_transform.translation(),
            Billboard::XZ => Vec3::new(target.x, transform.translation.y, target.z),
        };

        transform.look_at(target, Vec3::Y);
    }
}
