use rand::prelude::*;
use rusty_engine::prelude::*;

const PLAYER_SPEED: f32 = 400.0;
const ROAD_SPEED: f32 = 600.0;

#[derive(Resource)]
struct GameState {
    health_amount_p1: u8,
    health_amount_p2: u8,
    lost: bool,
}

impl Default for GameState {
    fn default() -> Self {
        Self {
            health_amount_p1: 5,
            health_amount_p2: 5,
            lost: false,
        }
    }
}

fn main() {
    let mut game = Game::new();

    game.audio_manager
        .play_music(MusicPreset::WhimsicalPopsicle, 0.2);

    let health_message_p1 = game.add_text("health_message_p1", "Health P1: 5");
    health_message_p1.translation = Vec2::new(-550.0, 320.0);

    let health_message_p2 = game.add_text("health_message_p2", "Health P2: 5");
    health_message_p2.translation = Vec2::new(-550.0, 280.0);

    let player1 = game.add_sprite("player1", SpritePreset::RacingCarBlue);
    player1.translation.x = -500.0;
    player1.translation.y = 50.0;
    player1.layer = 10.0;
    player1.collision = true;

    let player2 = game.add_sprite("player2", SpritePreset::RacingCarRed);
    player2.translation.x = -500.0;
    player2.translation.y = -50.0;
    player2.layer = 10.0;
    player2.collision = true;

    for i in 0..10 {
        let roadline = game.add_sprite(format!("roadline{}", i), SpritePreset::RacingBarrierWhite);
        roadline.scale = 0.1;
        roadline.translation.x = -350.0 + 150.0 * i as f32;
    }

    let obstacle_presets = [
        SpritePreset::RacingBarrelBlue,
        SpritePreset::RacingBarrelRed,
        SpritePreset::RacingConeStraight,
        SpritePreset::RacingBarrierRed,
        SpritePreset::RacingBarrierWhite,
    ];
    for (i, preset) in obstacle_presets.into_iter().enumerate() {
        let obstacle = game.add_sprite(format!("obstacle{}", i), preset);
        obstacle.layer = 5.0;
        obstacle.collision = true;
        obstacle.translation.x = rand::thread_rng().gen_range(800.0..1600.0);
        obstacle.translation.y = rand::thread_rng().gen_range(-300.0..300.0);
    }

    game.add_logic(game_logic);
    game.run(GameState::default());
}

fn game_logic(engine: &mut Engine, game_state: &mut GameState) {
    if game_state.lost {
        return;
    }

    let mut direction_player1: f32 = 0.0;
    if engine.keyboard_state.pressed_any(&[KeyCode::ArrowUp]) {
        direction_player1 += 1.0
    }
    if engine.keyboard_state.pressed_any(&[KeyCode::ArrowDown]) {
        direction_player1 -= 1.0
    }

    let player1 = engine.sprites.get_mut("player1").unwrap();
    player1.translation.y += direction_player1 * PLAYER_SPEED * engine.delta_f32;
    player1.rotation = direction_player1 * 0.15;

    if player1.translation.y.abs() > 360.0 {
        game_state.health_amount_p1 = 0;
    }

    let _ = player1;

    let mut direction_player2: f32 = 0.0;
    if engine.keyboard_state.pressed_any(&[KeyCode::KeyW]) {
        direction_player2 += 1.0
    }
    if engine.keyboard_state.pressed_any(&[KeyCode::KeyS]) {
        direction_player2 -= 1.0
    }

    let player2 = engine.sprites.get_mut("player2").unwrap();
    player2.translation.y += direction_player2 * PLAYER_SPEED * engine.delta_f32;
    player2.rotation = direction_player2 * 0.15;

    if player2.translation.y.abs() > 360.0 {
        game_state.health_amount_p2 = 0;
    }

    let _ = player2;

    for sprite in engine.sprites.values_mut() {
        if sprite.label.starts_with("roadline") {
            sprite.translation.x -=
                (ROAD_SPEED * engine.delta_f32) + (engine.time_since_startup_f64 as f32 / 10.0);
            if sprite.translation.x < -675.0 {
                sprite.translation.x += 1500.0;
            }
        }

        if sprite.label.starts_with("obstacle") {
            sprite.translation.x -=
                (ROAD_SPEED * engine.delta_f32) + (engine.time_since_startup_f64 as f32 / 10.0);
            if sprite.translation.x < -800.0 {
                sprite.translation.x = rand::thread_rng().gen_range(800.0..1600.0);
                sprite.translation.y = rand::thread_rng().gen_range(-300.0..300.0);
            }
        }
    }

    for event in engine.collision_events.drain(..) {
        if event.state.is_end() {
            continue;
        }

        if event.pair.either_contains("obstacle") {
            if event.pair.either_contains("player1") {
                game_state.health_amount_p1 -= 1;

                let health_message_p1 = engine.texts.get_mut("health_message_p1").unwrap();
                health_message_p1.value = format!("Health P1: {}", game_state.health_amount_p1);
            }

            if event.pair.either_contains("player2") {
                game_state.health_amount_p2 -= 1;
                let health_message_p2 = engine.texts.get_mut("health_message_p2").unwrap();
                health_message_p2.value = format!("Health P2: {}", game_state.health_amount_p2);
            }

            engine.audio_manager.play_sfx(SfxPreset::Impact3, 0.5);
        }
    }

    if game_state.health_amount_p1 == 0 || game_state.health_amount_p2 == 0 {
        game_state.lost = true;

        let game_over = engine.add_text("game_over", "Game Over");
        game_over.font_size = 128.0;
        game_over.translation.x = 0.0;
        game_over.translation.y = 0.0;
        engine.audio_manager.stop_music();
        engine.audio_manager.play_sfx(SfxPreset::Jingle3, 0.5);
    }
}
