use bevy::prelude::*;
use rand::Rng;

const GRAVITY: f32 = -20.0;
const FLAP_STRENGTH: f32 = 12.0;
const MOVE_SPEED: f32 = 10.0;
const ARENA_HALF: f32 = 22.0;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "Bird PvP".into(),
                resolution: (1280., 720.).into(),
                ..default()
            }),
            ..default()
        }))
        .insert_resource(Scoreboard::default())
        .insert_resource(ClearColor(Color::srgb(0.2, 0.6, 1.0)))
        .add_systems(Startup, setup)
        .add_systems(
            Update,
            (
                player_input,
                bird_physics,
                bird_vs_bird_collision,
                arena_collision,
                ui_update,
            ),
        )
        .run();
}

#[derive(Resource, Default)]
struct Scoreboard {
    p1: u32,
    p2: u32,
}

#[derive(Component)]
struct Bird {
    velocity: Vec3,
    player_id: usize,
}

#[derive(Component)]
struct ScoreText;

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // LIGHT
    commands.spawn(PointLightBundle {
        point_light: PointLight {
            intensity: 4000.0,
            range: 200.,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(20.0, 30.0, 20.0),
        ..default()
    });

    // GROUND
    commands.spawn(PbrBundle {
        mesh: meshes.add(Plane3d::default().mesh().size(60.0, 60.0)),
        material: materials.add(Color::srgb(0.1, 0.7, 0.1)),
        transform: Transform::from_xyz(0.0, -1.0, 0.0),
        ..default()
    });

    // PLAYER 1 — red bird
    commands.spawn((
        SceneBundle {
            scene: asset_server.load("models/bird.glb#Scene0"),
            transform: Transform::from_xyz(-5.0, 2.0, 0.0).with_scale(Vec3::splat(0.15)),
            ..default()
        },
        Bird {
            velocity: Vec3::ZERO,
            player_id: 1,
        },
    ));

    // PLAYER 2 — blue bird
    commands.spawn((
        SceneBundle {
            scene: asset_server.load("models/bird.glb#Scene0"),
            transform: Transform::from_xyz(5.0, 2.0, 0.0).with_scale(Vec3::splat(0.15)),
            ..default()
        },
        Bird {
            velocity: Vec3::ZERO,
            player_id: 2,
        },
    ));

    // CAMERA
    commands.spawn(Camera3dBundle {
        transform: Transform::from_xyz(0.0, 30.0, 30.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });

    // UI
    commands.spawn((
        TextBundle::from_section(
            "P1: 0    P2: 0",
            TextStyle {
                font_size: 40.0,
                color: Color::WHITE,
                ..default()
            },
        ),
        ScoreText,
    ));
}

// ----------------------------------------------
// PLAYER INPUT
// ----------------------------------------------

fn player_input(input: Res<ButtonInput<KeyCode>>, mut birds: Query<(&mut Bird, &mut Transform)>) {
    for (mut bird, mut tf) in &mut birds {
        let mut move_x = 0.0;
        let mut flap = false;

        match bird.player_id {
            1 => {
                if input.pressed(KeyCode::KeyA) {
                    move_x -= 1.0;
                }
                if input.pressed(KeyCode::KeyD) {
                    move_x += 1.0;
                }
                if input.just_pressed(KeyCode::KeyW) {
                    flap = true;
                }
            }
            2 => {
                if input.pressed(KeyCode::ArrowLeft) {
                    move_x -= 1.0;
                }
                if input.pressed(KeyCode::ArrowRight) {
                    move_x += 1.0;
                }
                if input.just_pressed(KeyCode::ArrowUp) {
                    flap = true;
                }
            }
            _ => {}
        }

        if flap {
            bird.velocity.y = FLAP_STRENGTH;
        }

        tf.translation.x += move_x * MOVE_SPEED * 0.016;
    }
}

// ----------------------------------------------
// PHYSICS
// ----------------------------------------------

fn bird_physics(time: Res<Time>, mut q: Query<(&mut Bird, &mut Transform)>) {
    for (mut bird, mut tf) in &mut q {
        bird.velocity.y += GRAVITY * time.delta_seconds();
        tf.translation += bird.velocity * time.delta_seconds();
    }
}

// ----------------------------------------------
// BIRD VS BIRD COLLISION
// ----------------------------------------------

fn bird_vs_bird_collision(mut birds: Query<(&mut Bird, &Transform)>) {
    let mut iter = birds.iter_mut();

    let Some((mut a, tf_a)) = iter.next() else {
        return;
    };
    let Some((mut b, tf_b)) = iter.next() else {
        return;
    };

    let diff = tf_b.translation - tf_a.translation;
    let dist = diff.length();

    if dist < 1.5 {
        let push = diff.normalize() * 10.0;
        a.velocity -= push;
        b.velocity += push;
    }
}

// ----------------------------------------------
// WALL COLLISION + SCORING
// ----------------------------------------------

fn arena_collision(
    mut birds: Query<(&mut Transform, &mut Bird)>,
    mut scoreboard: ResMut<Scoreboard>,
) {
    for (mut tf, mut bird) in &mut birds {
        if tf.translation.x.abs() > ARENA_HALF
            || tf.translation.z.abs() > ARENA_HALF
            || tf.translation.y < -2.0
            || tf.translation.y > 15.0
        {
            match bird.player_id {
                1 => scoreboard.p2 += 1,
                2 => scoreboard.p1 += 1,
                _ => {}
            }

            // Respawn
            tf.translation = Vec3::new(rand::thread_rng().gen_range(-5.0..5.0), 2.0, 0.0);
            bird.velocity = Vec3::ZERO;
        }
    }
}

// ----------------------------------------------
// UI UPDATE
// ----------------------------------------------

fn ui_update(scoreboard: Res<Scoreboard>, mut text: Query<&mut Text, With<ScoreText>>) {
    let mut ui = text.single_mut();
    ui.sections[0].value = format!("P1: {}    P2: {}", scoreboard.p1, scoreboard.p2);
}
