use bevy::{input::mouse::MouseWheel, prelude::*};
use bevy_flycam::prelude::*;

// From bevy examples:
// https://github.com/bevyengine/bevy/blob/latest/examples/3d/3d_scene.rs

#[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)]
enum ScrollType {
    #[default]
    MovementSpeed,
    Zoom,
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        //NoCameraPlayerPlugin as we provide the camera
        .add_plugins(NoCameraPlayerPlugin)
        .insert_resource(MovementSettings {
            ..Default::default()
        })
        // Setting initial state
        .init_state::<ScrollType>()
        .add_systems(Startup, setup)
        .add_systems(Update, switch_scroll_type)
        .add_systems(Update, scroll)
        .run();
}

/// set up a simple 3D scene
fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // plane
    commands.spawn((
        Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(2.5)))),
        MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))),
    ));

    // cube
    commands.spawn((
        Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
        MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),
        Transform::from_xyz(0.0, 0.5, 0.0),
    ));

    // light
    // light
    commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 8.0, 4.0)));

    // add camera
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(-2.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
        FlyCam,
    ));

    info!("Press 'Z' to switch between Movement Speed and Zoom");
    info!("Changing the selected value by scrolling the mousewheel");
}

/// Listens for Z key being pressed and toggles between the two scroll-type states [`ScrollType`]
fn switch_scroll_type(
    scroll_type: Res<State<ScrollType>>,
    mut next_scroll_type: ResMut<NextState<ScrollType>>,
    keyboard_input: Res<ButtonInput<KeyCode>>,
) {
    if keyboard_input.just_pressed(KeyCode::KeyZ) {
        let result = match scroll_type.get() {
            ScrollType::MovementSpeed => ScrollType::Zoom,
            ScrollType::Zoom => ScrollType::MovementSpeed,
        };

        println!("{:?}", result);
        next_scroll_type.set(result);
    }
}

/// Depending on the state, the mouse-scroll changes either the movement speed or the field-of-view of the camera
fn scroll(
    mut settings: ResMut<MovementSettings>,
    scroll_type: Res<State<ScrollType>>,
    mut mouse_wheel_events: EventReader<MouseWheel>,
    mut query: Query<(&FlyCam, &mut Projection)>,
) {
    for event in mouse_wheel_events.read() {
        if *scroll_type.get() == ScrollType::MovementSpeed {
            settings.speed = (settings.speed + event.y * 0.1).abs();
            println!("Speed: {:?}", settings.speed);
        } else {
            for (_camera, project) in query.iter_mut() {
                if let Projection::Perspective(perspective) = project.into_inner() {
                    perspective.fov = (perspective.fov - event.y * 0.01).abs();
                    println!("FOV: {:?}", perspective.fov);
                }
            }
        }
    }
}