use crate::{
    GameState,
    ai::Ai,
    character::AnimatedCharacter,
    head::ActiveHead,
    head_drop::HeadDrops,
    heads::{ActiveHeads, HEAD_COUNT, HeadState},
    heads_database::HeadsDatabase,
    hitpoints::{Hitpoints, Kill},
    keys::KeySpawn,
    tb_entities::EnemySpawn,
};
use bevy::prelude::*;
use std::collections::HashMap;

#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct Npc;

pub fn plugin(app: &mut App) {
    app.add_systems(OnEnter(GameState::Playing), init);
}

fn init(mut commands: Commands, query: Query<(Entity, &EnemySpawn)>, heads_db: Res<HeadsDatabase>) {
    //TODO: move into HeadsDatabase
    let mut names: HashMap<String, usize> = HashMap::default();
    for i in 0..HEAD_COUNT {
        names.insert(heads_db.head_key(i).to_string(), i);
    }

    for (e, spawn) in query.iter() {
        let id = names[&spawn.head];
        commands
            .entity(e)
            .insert((
                Hitpoints::new(100),
                Npc,
                ActiveHead(id),
                ActiveHeads::new([
                    Some(HeadState::new(id, heads_db.as_ref())),
                    None,
                    None,
                    None,
                    None,
                ]),
            ))
            .insert_if(Ai, || !spawn.disable_ai)
            .with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
            .observe(on_kill);
    }
}

fn on_kill(
    trigger: Trigger<Kill>,
    mut commands: Commands,
    query: Query<(&Transform, &EnemySpawn, &ActiveHead)>,
) {
    let Ok((transform, enemy, head)) = query.get(trigger.target()) else {
        return;
    };

    commands.trigger(HeadDrops::new(transform.translation, head.0));

    commands.entity(trigger.target()).despawn();

    if !enemy.key.is_empty() {
        commands.trigger(KeySpawn(transform.translation, enemy.key.clone()));
    }
}
