/*
    Hurry Curry! - a game about cooking
    Copyright (C) 2026 Hurry Curry! Contributors

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

*/
use super::{Entity, EntityContext, bot::BotDriver};
use anyhow::Result;
use hurrycurry_bot::algos::Customer;
use hurrycurry_locale::TrError;
use hurrycurry_protocol::{Character, PlayerClass, TileIndex};
use rand::random;

pub struct Customers {
    customers: Vec<BotDriver<Customer>>,
    current_spawn_cooldown: f32,
    spawn_cooldown: f32,
    chair_count: Option<usize>,
    scaling_factor: f32,
}

impl Customers {
    pub fn new(scaling_factor: f32, spawn_cooldown: f32) -> Self {
        Self {
            customers: Vec::new(),
            current_spawn_cooldown: 0.,
            spawn_cooldown,
            chair_count: None,
            scaling_factor,
        }
    }
}

impl Entity for Customers {
    fn tick(&mut self, mut c: EntityContext) -> Result<(), TrError> {
        let chairs = *self.chair_count.get_or_insert_with(|| {
            c.game
                .tile_index
                .get(
                    &c.game
                        .data
                        .get_tile_by_name("chair")
                        .unwrap_or(TileIndex(0)),
                )
                .map_or(0, |c| c.len())
        });
        let max_count = (self.scaling_factor * chairs as f32).max(1.) as usize;

        self.current_spawn_cooldown -= c.dt;
        self.current_spawn_cooldown = self.current_spawn_cooldown.max(0.);
        if self.customers.len() < max_count && self.current_spawn_cooldown <= 0. {
            self.current_spawn_cooldown =
                self.spawn_cooldown + random::<f32>() * self.spawn_cooldown;
            let bot = BotDriver::new(
                "".to_string(),
                Character {
                    color: random(),
                    hairstyle: random(),
                    headwear: 0,
                },
                PlayerClass::Customer,
                Customer::new,
            );
            self.customers.push(bot)
        }
        for bot in &mut self.customers {
            bot.tick(c.dup())?;
        }
        self.customers.retain(|c| !c.finished());
        Ok(())
    }

    fn destructor(&mut self, mut c: EntityContext<'_>) {
        for mut e in self.customers.drain(..) {
            e.destructor(c.dup());
        }
    }
}
