use bevy::prelude::*;

use crate::{
    core::{
        bubble::Bubble,
        counter::{BubbleExplodedCountThisFrame, BubbleSuckedCountThisFrame, KirbyHitCountThisFrame},
        game_state::DispawnOnGameOver,
        kirby::{Kirby, SuckArea},
    },
    physics::sphere_collider::SphereCollider,
};

#[derive(Component)]
#[require(DispawnOnGameOver)]
pub struct Life {
    max_life: f32,
    current_life: f32,
}

impl Life {
    pub fn new(max_life: f32) -> Self {
        Self { max_life, current_life: max_life }
    }

    pub fn damage(&mut self, amount: f32) {
        self.current_life -= amount;
    }

    pub fn heal(&mut self, amount: f32) {
        self.current_life = (self.current_life + amount).min(self.max_life);
    }
}

impl Default for Life {
    fn default() -> Self {
        Life::new(100.0)
    }
}

pub fn despawn_if_dead(mut commands: Commands, query: Query<(Entity, &Life)>) {
    for (entity, life) in query.iter() {
        if life.current_life < 0.0 {
            commands.entity(entity).despawn();
        }
    }
}

#[derive(Component, Default)]
#[require(SphereCollider, DispawnOnGameOver)]
pub struct DamageDealer {
    damage_strength: f32,
}

impl DamageDealer {
    pub fn new(damage: f32) -> Self {
        DamageDealer { damage_strength: damage }
    }
}

// Considerating ennemies are ponctual
pub fn bubble_receive_damage(
    time: Res<Time<Fixed>>,
    mut bubble_sucked: ResMut<BubbleSuckedCountThisFrame>,
    mut enemy_query: Query<(&GlobalTransform, &mut Life), With<Bubble>>,

    kirby_query: Query<(&Kirby, &Children)>,
    suck_area_query: Query<(&GlobalTransform, &SphereCollider, &DamageDealer), With<SuckArea>>,
) {
    for (kirby, children) in &kirby_query {
        if !kirby.is_sucking {
            continue;
        }

        for child in children.iter() {
            let Ok((suck_transform, suck_collider, suck_damage)) = suck_area_query.get(child) else {
                continue;
            };

            for (enemy_transform, mut enemy_life) in &mut enemy_query {
                if suck_collider.point_inside(suck_transform.translation(), enemy_transform.translation()) {
                    enemy_life.damage(suck_damage.damage_strength * time.delta_secs());
                    bubble_sucked.increase(1);
                }
            }
        }
    }
}

// Considerating allies are ponctual
pub fn kirby_receive_damage(
    mut bubble_exploded: ResMut<BubbleExplodedCountThisFrame>,
    mut kirby_hit: ResMut<KirbyHitCountThisFrame>,
    mut kirby_query: Query<(&Kirby, &GlobalTransform, &mut Life), Without<Bubble>>,
    mut bubble_query: Query<
        (&GlobalTransform, &SphereCollider, &DamageDealer, &mut Life),
        (With<Bubble>, Without<Kirby>),
    >,
) {
    for (kirby, kirby_transform, mut kirby_life) in &mut kirby_query {
        for (bubble_transform, bubble_sphere_collider, bubble_damage_dealer, mut bubble_life) in &mut bubble_query {
            if bubble_sphere_collider.point_inside(kirby_transform.translation(), bubble_transform.translation()) {
                kirby_life.damage(bubble_damage_dealer.damage_strength * kirby.shield_factor);
                bubble_life.damage(1000000.0); // Bubble explode
                // println!("{:?}", kirby_life.current_life)
                bubble_exploded.increase(1);
                kirby_hit.increase(1);
            }
        }
    }
}
