use bevy::{
    core_pipeline::Skybox,
    input::mouse::MouseMotion,
    prelude::*,
    render::render_resource::{TextureViewDescriptor, TextureViewDimension},
};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, init)
        .add_systems(Update, (add_skybox, move_camera))
        .run()
}

fn init(mut commands: Commands) {
    commands.spawn(Camera3dBundle {
        camera: Camera {
            is_active: true,
            ..default()
        },
        ..default()
    });
}

fn add_skybox(
    server: Res<AssetServer>,
    query: Query<Entity, With<Camera>>,
    mut images: ResMut<Assets<Image>>,
    mut commands: Commands,
    mut handle: Local<Option<Handle<Image>>>,
    mut loaded: Local<bool>,
) {
    if !(*loaded) {
        if let Some(handle) = (*handle).clone() {
            if let Some(image) = images.get_mut(&handle) {
                info!("Loaded skybox image");
                // NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture,
                // so they appear as one texture. The following code reconfigures the texture as necessary.
                if image.texture_descriptor.array_layer_count() == 1 {
                    image.reinterpret_stacked_2d_as_array(
                        image.texture_descriptor.size.height / image.texture_descriptor.size.width,
                    );
                    image.texture_view_descriptor = Some(TextureViewDescriptor {
                        dimension: Some(TextureViewDimension::Cube),
                        ..default()
                    });
                }
                query.iter().for_each(|entity| {
                    commands.entity(entity).insert(Skybox(handle.clone()));
                });
                *loaded = true;
            }
        } else {
            *handle = Some(server.load("images/skybox.png"));
        }
    }
}

fn move_camera(
    mut events: EventReader<MouseMotion>,
    mut camera: Query<&mut Transform, With<Camera>>,
) {
    events.iter().for_each(|MouseMotion { delta }| {
        camera.iter_mut().for_each(|mut t| {
            t.rotate_local_y(-delta.x / 256.0);
            t.rotate_local_x(-delta.y / 256.0);
        })
    });
}
