//! The write side of the behavior engine. Everything a behavior wants to DO beyond mutating
//! its own projectile and the one enemy it hit becomes a `Command`. Pushed during a pass,
//! drained and applied after. Payoffs: no borrow conflict, one deterministic apply point, and
//! the ability to affect entities you only have READ access to.

use macroquad::math::Vec2;

use crate::{
    animations::Animation,
    context::DamageMap,
    enemy::Enemy,
    pool::GroundPool,
    registry::StatusApplication,
    types::{DamageDelivery, GameEvent, ResourceKind, Source},
    world::{EntityId, Projectile},
};

pub enum TransformEntity {
    Enemy,
}
pub struct Transform {
    pub entity: TransformEntity,
    pub id: EntityId,
    pub location: Vec2,
}

pub enum Command {
    SpawnProjectile(Projectile),
    SpawnPool(GroundPool),
    SpawnEnemy(Enemy), // e.g. an enemy that s plits on death
    Damage {
        target: EntityId,
        amount: DamageMap,
        source: Source,
        delivery: DamageDelivery,
    },
    ApplyStatus {
        target: EntityId,
        status: StatusApplication,
    },
    Despawn(EntityId),
    GrantResource {
        kind: ResourceKind,
        amount: u32,
    },
    Emit(GameEvent), // feeds the SP PassiveEffect bus + UI
    SpawnAnimation(Animation),
    Replicate(Transform),
}

#[derive(Default)]
pub struct CommandBuffer {
    pub cmds: Vec<Command>,
}
impl CommandBuffer {
    pub fn spawn_projectile(&mut self, p: Projectile) {
        self.cmds.push(Command::SpawnProjectile(p));
    }
    pub fn spawn_pool(&mut self, p: GroundPool) {
        self.cmds.push(Command::SpawnPool(p));
    }
    pub fn spawn_enemy(&mut self, e: Enemy) {
        self.cmds.push(Command::SpawnEnemy(e));
    }
    pub fn damage(
        &mut self,
        t: EntityId,
        amount: DamageMap,
        source: Source,
        delivery: DamageDelivery,
    ) {
        self.cmds.push(Command::Damage {
            target: t,
            amount,
            source,
            delivery,
        });
    }
    pub fn apply_status(&mut self, t: EntityId, status: StatusApplication) {
        self.cmds.push(Command::ApplyStatus { target: t, status });
    }

    pub fn grant_resource(&mut self, kind: ResourceKind, amount: u32) {
        self.cmds.push(Command::GrantResource { kind, amount });
    }
    pub fn despawn(&mut self, t: EntityId) {
        self.cmds.push(Command::Despawn(t));
    }
    pub fn emit(&mut self, e: GameEvent) {
        self.cmds.push(Command::Emit(e));
    }
    pub fn spawn_animation(&mut self, a: Animation) {
        self.cmds.push(Command::SpawnAnimation(a));
    }
    pub fn replicate(&mut self, t: Transform) {
        self.cmds.push(Command::Replicate(t));
    }
}
