use bevy::prelude::*;

use crate::sounds::PlaySound;

#[derive(Event, Reflect)]
pub struct Kill;

#[derive(Event, Reflect)]
pub struct Hit {
    pub damage: u32,
}

#[derive(Component, Reflect, Debug, PartialEq, Eq, Clone, Copy)]
pub struct Hitpoints {
    max: u32,
    current: u32,
}

impl Hitpoints {
    pub fn new(v: u32) -> Self {
        Self { max: v, current: v }
    }

    pub fn with_health(mut self, v: u32) -> Self {
        self.current = v;
        self
    }

    pub fn health(&self) -> f32 {
        self.current as f32 / self.max as f32
    }

    pub fn set_health(&mut self, v: u32) {
        self.current = v;
    }

    pub fn heal(&mut self, v: u32) {
        self.current += v;
    }

    pub fn get(&self) -> (u32, u32) {
        (self.current, self.max)
    }

    pub fn max(&self) -> bool {
        self.current == self.max
    }
}

pub fn plugin(app: &mut App) {
    app.add_systems(Update, on_hp_added);
}

fn on_hp_added(mut commands: Commands, query: Query<Entity, Added<Hitpoints>>) {
    for e in query.iter() {
        commands.entity(e).observe(on_hit);
    }
}

fn on_hit(trigger: Trigger<Hit>, mut commands: Commands, mut query: Query<&mut Hitpoints>) {
    let Hit { damage } = trigger.event();

    let Ok(mut hp) = query.get_mut(trigger.target()) else {
        return;
    };

    commands.trigger(PlaySound::Hit);

    hp.current = hp.current.saturating_sub(*damage);

    if hp.current == 0 {
        commands.trigger_targets(Kill, trigger.target());
    }
}
