use std::path::Path;
use std::time::Duration;

use crate::core::game_state::DispawnOnGameOver;
use crate::core::kirby::{Kirby, kirby_spawn};
use crate::juice::sound::Poyoo;
use crate::physics::sphere_collider::SphereCollider;
use bevy::prelude::*;
use bevy_kira_audio::{AudioChannel, AudioControl};

const ASSETS_NAME: [&str; 3] = ["speed_item.png", "shield_item.png", "kirby_item.png"];
const COLLECTABLE_COLLIDER_RADIUS: f32 = 50.0;
const KIRBY_SPAWN_TIMER_DURATION: Duration = Duration::from_secs(2);
pub const COLLECTABLE_SCALE: f32 = 2.5;

#[derive(Clone, Copy)]
pub enum CollectableType {
    SpeedBoost = 0,
    ShieldBoost = 1,
    NewKirby = 2,
}

#[derive(Component)]
#[require(SphereCollider, Sprite, DispawnOnGameOver)]
pub struct Collectable(CollectableType);

pub fn collectable_spawn(
    commands: &mut Commands,
    asset_server: &Res<AssetServer>,
    collectable_type: CollectableType,
    pos: Vec2,
) {
    let asset_name = ASSETS_NAME[collectable_type as usize];
    let asset_path = Path::new("sprites").join(asset_name);
    let sprite = Sprite::from_image(asset_server.load(asset_path));
    commands.spawn((
        Collectable(collectable_type),
        SphereCollider::new(COLLECTABLE_COLLIDER_RADIUS),
        Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(COLLECTABLE_SCALE)),
        sprite,
    ));
}

pub fn collectable_actions_system(
    mut commands: Commands,
    mut kirby_query: Query<(&mut Kirby, &SphereCollider, &Transform)>,
    collectable_query: Query<(Entity, &Collectable, &SphereCollider, &Transform)>,
    asset_server: Res<AssetServer>,
) {
    for (mut kirby, kirby_collider, kirby_tf) in &mut kirby_query {
        for (collectible_entity, collectible, c_collider, collectable_tf) in collectable_query {
            let collides = c_collider.collides(collectable_tf.translation, kirby_collider, kirby_tf.translation);
            let kirby_pos = kirby_tf.translation;
            if !collides {
                continue;
            }

            match &collectible.0 {
                CollectableType::SpeedBoost => speed_boost(&mut kirby),
                CollectableType::ShieldBoost => shield_boost(&mut kirby),
                CollectableType::NewKirby => new_kirby(kirby_pos, &mut commands, &asset_server),
            }

            commands.entity(collectible_entity).despawn();
        }
    }
}

fn speed_boost(kirby: &mut Kirby) {
    kirby.speed_force *= 1.2;
}

fn shield_boost(kirby: &mut Kirby) {
    kirby.shield_factor *= 0.8;
}

fn new_kirby(kirby_pos: Vec3, commands: &mut Commands, asset_server: &Res<AssetServer>) {
    commands.spawn((
        KirbySpawnHandler { timer: Timer::new(KIRBY_SPAWN_TIMER_DURATION, TimerMode::Once), position: kirby_pos },
        Sprite::from_image(asset_server.load("sprites/timer.png")),
        Transform::from_translation(kirby_pos).with_scale(Vec3::splat(COLLECTABLE_SCALE)),
    ));
}

#[derive(Component)]
#[require(DispawnOnGameOver, Sprite, Transform)]
struct KirbySpawnHandler {
    timer: Timer,
    position: Vec3,
}

// After player get new_kirby item, it should spawn a new_kirby after a certain time
fn kirby_spawn_timer(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
    query: Query<(&mut KirbySpawnHandler, Entity)>,
    time: Res<Time>,
    poyoo_chan: Res<AudioChannel<Poyoo>>,
) {
    for (mut kirby_spawn_handler, kirby_spawn_entity) in query {
        kirby_spawn_handler.timer.tick(time.delta());
        if kirby_spawn_handler.timer.is_finished() {
            kirby_spawn(&mut commands, &asset_server, &mut texture_atlas_layouts, kirby_spawn_handler.position);
            poyoo_chan.play(asset_server.load("sounds/kirby-poyo.ogg"));
            commands.entity(kirby_spawn_entity).despawn();
        }
    }
}
pub struct CollectablePlugin;

impl Plugin for CollectablePlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(FixedUpdate, collectable_actions_system).add_systems(Update, kirby_spawn_timer);
    }
}
