use avian3d::prelude::*;
use bevy::{core_pipeline::Skybox, prelude::*, render::render_resource::AsBindGroupShaderType};
use leafwing_input_manager::prelude::*;

use crate::{
    input::{self, Action},
    mouse_joy::MouseJoy,
    skybox::SkyCubeMap,
};

#[derive(Component)]
pub struct Player;

pub fn set_up_player(mut commands: Commands, assets: ResMut<AssetServer>) {
    let skybox = assets.load("skybox.png");
    let player_transform = Transform::from_xyz(0.0, 0.0, 0.0);
    let camera_transform = Transform::from_xyz(0.0, 4.0, 20.0);
    let player = assets.load("Racer.glb#Scene0");
    commands.insert_resource(SkyCubeMap {
        is_loaded: false,
        image_handle: skybox.clone(),
    });

    commands
        .spawn(SceneBundle {
            scene: player,
            transform: player_transform.clone(),
            ..default()
        })
        .insert(InputManagerBundle::with_map(input::default_input_map()))
        .insert(Player)
        .insert(Collider::sphere(1.0))
        .insert(RigidBody::Dynamic)
        .insert(ExternalForce::default().with_persistence(false))
        .insert(ExternalTorque::default().with_persistence(false))
        .insert(LinearVelocity::default())
        .insert(LinearDamping(0.01))
        .insert(AngularDamping(3.0))
        .with_children(|parent| {
            parent.spawn((
                Camera3dBundle {
                    transform: camera_transform,
                    ..default()
                },
                Skybox {
                    image: skybox,
                    brightness: 100.0,
                },
            ));
        });
}

pub fn quit_game(mut exit: EventWriter<AppExit>, mut query: Query<&mut ActionState<Action>>) {
    let (actions) = query.single_mut();
    if actions.pressed(&Action::Quit) {
        exit.send(AppExit::Success);
    }
}
pub fn move_player(
    mut query: Query<(
        &mut Player,
        &Transform,
        &mut ExternalForce,
        &mut ExternalTorque,
        &LinearVelocity,
        &ActionState<Action>,
    )>,
    joy: Res<MouseJoy>,
    time: Res<Time>,
) {
    let speed = 200.0;
    let key_multiplier = 10.0;
    let turn_speed = 300.0;
    let brake_speed = 50.0;
    let dt = time.delta_seconds();
    let (mut player, xform, mut force, mut torque, velocity, actions) = query.single_mut();
    let strafe = actions.axis_pair(&Action::StrafeXZ);
    let mut momentum = key_multiplier
        * (xform.right().as_vec3() * strafe[0] + xform.forward().as_vec3() * strafe[1]);
    if actions.pressed(&Action::StrafePosX) {
        momentum = momentum + key_multiplier * xform.right().as_vec3();
    }

    if actions.pressed(&Action::StrafeNegX) {
        momentum = momentum + key_multiplier * xform.left().as_vec3();
    }
    if actions.pressed(&Action::StrafePosY) {
        momentum = momentum + key_multiplier * xform.up().as_vec3();
    }

    if actions.pressed(&Action::StrafeNegY) {
        momentum = momentum + key_multiplier * xform.down().as_vec3();
    }
    if actions.pressed(&Action::StrafePosZ) {
        momentum = momentum + key_multiplier * xform.forward().as_vec3();
    }

    if actions.pressed(&Action::StrafeNegZ) {
        momentum = momentum + key_multiplier * xform.back().as_vec3();
    }
    if actions.pressed(&Action::Brake) {
        momentum -= velocity.0 * dt * brake_speed;
    }
    force.apply_force(momentum * speed * dt);
    let mut pya = actions.axis_pair(&Action::PitchYaw);
    pya.y *= -1.0;
    let py = pya + joy.0;

    torque.apply_torque(dt * turn_speed * (xform.down() * py.x + xform.left() * py.y));
    let mut roll = 0.0;
    if actions.pressed(&Action::PosRoll) {
        roll += turn_speed;
    }

    if actions.pressed(&Action::NegRoll) {
        roll -= turn_speed;
    }
    torque.apply_torque(key_multiplier * 0.5 * xform.forward() * dt * roll);
}