use crate::{
    GameState, global_observer, heads::ActiveHeads, heads_database::HeadsDatabase,
    hitpoints::Hitpoints,
};
use bevy::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Component, Serialize, Deserialize, PartialEq)]
pub struct Healing;

#[derive(Clone, Event, Debug, Serialize, Deserialize)]
pub enum HealingStateChanged {
    Started,
    Stopped,
}

pub fn plugin(app: &mut App) {
    app.add_systems(Update, update.run_if(in_state(GameState::Playing)));

    global_observer!(app, on_heal_start_stop);
}

fn on_heal_start_stop(
    trigger: Trigger<HealingStateChanged>,
    mut cmds: Commands,
    query: Query<&Healing>,
) {
    if matches!(trigger.event(), HealingStateChanged::Started) {
        if query.contains(trigger.target()) {
            // already healing, just ignore
            return;
        }

        cmds.entity(trigger.target()).insert(Healing);
    } else {
        if !query.contains(trigger.target()) {
            // Not healing, just ignore
            return;
        }

        cmds.entity(trigger.target()).remove::<Healing>();
    }
}

fn update(
    mut query: Query<(&mut ActiveHeads, &mut Hitpoints), With<Healing>>,
    time: Res<Time>,
    heads_db: Res<HeadsDatabase>,
) {
    for (mut heads, mut hitpoints) in query.iter_mut() {
        let Some(current) = heads.current() else {
            continue;
        };

        let head = heads_db.head_stats(current.head);

        if current.last_use + (1. / head.aps) > time.elapsed_secs() {
            continue;
        }

        let medic_hp = hitpoints.get().0;
        if medic_hp > 0 {
            if let Some(health) = heads.medic_heal(2, time.elapsed_secs()) {
                hitpoints.set_health(health);
            } else {
                continue;
            }
        }
    }
}
