use bevy::{ecs::system::SystemParam, prelude::*};
use bevy_kira_audio::prelude::*;

use crate::{
    core::{
        kirby::Kirby,
        wave::{BubbleWaves, EnnemyWaveLock},
    },
    juice::sound::{Background, Poyoo},
};

#[derive(Event)]
pub struct EndGameEvent {
    pub reason: EndGameReason,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EndGameReason {
    Die,
    Victory,
}

fn no_kirbies_emetter(mut commands: Commands, query: Query<(), With<Kirby>>) {
    if query.is_empty() {
        commands.trigger(EndGameEvent { reason: EndGameReason::Die });
    };
}

#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
pub enum GameState {
    #[default]
    Starting,
    Running,
    #[allow(dead_code)]
    Paused,
}

#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub struct GameStartupSet;

#[derive(Component, Default)]
pub struct DispawnOnGameOver;

pub trait Resetable {
    fn reset(&mut self);
}

fn reset_resource<T: Resource + Resetable>(mut res: ResMut<T>) {
    res.reset();
}

#[derive(SystemParam)]
struct GameRes<'w> {
    bubble_waves: ResMut<'w, BubbleWaves>,
    ennemy_wave_lock: ResMut<'w, EnnemyWaveLock>,
}

fn on_reset_world(
    _: On<ResetWorldEvent>,
    mut commands: Commands,
    entities: Query<Entity, With<DispawnOnGameOver>>,
    game_res: GameRes,
) {
    for e in &entities {
        commands.entity(e).despawn();
    }
    reset_resource(game_res.bubble_waves);
    reset_resource(game_res.ennemy_wave_lock);
    println!("Set state");
    commands.set_state(GameState::Starting);
}

#[derive(Event)]
struct ResetWorldEvent;

fn on_end_game(
    event: On<EndGameEvent>,
    mut commands: Commands,
    background_audio: Res<AudioChannel<Background>>,
    poyo_audio: Res<AudioChannel<Poyoo>>,
    asset_server: Res<AssetServer>,
) {
    let reason = event.reason;
    println!("end game reason {:?}", reason);

    if reason == EndGameReason::Victory {
        background_audio.stop();
        poyo_audio.play(asset_server.load("sounds/kirby-poyo.ogg"));
        background_audio.play(asset_server.load("sounds/end_goffy.ogg"));
        return;
    }
    commands.trigger(ResetWorldEvent);
}

fn change_to_running_state(mut commands: Commands) {
    println!("Running state !");
    commands.set_state(GameState::Running);
}

pub struct GameEventsPlugin;

impl Plugin for GameEventsPlugin {
    fn build(&self, app: &mut App) {
        app.init_state::<GameState>()
            .add_systems(Update, no_kirbies_emetter.run_if(in_state(GameState::Running)))
            .add_systems(OnEnter(GameState::Starting), change_to_running_state.after(GameStartupSet))
            .add_observer(on_end_game)
            .add_observer(on_reset_world);
    }
}
