// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use serde::Deserialize;
use strum::IntoEnumIterator;

use crate::server::common::config::{AmmoCountIo, Effects};
use crate::world::powerup::PowerupType;

#[derive(Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EventConfig {
	/**
	 * Radius of the square in which the players can spawn, respawn and teleport
	 * to.
	 */
	#[serde(default = "player_spawn_radius_default")] pub player_spawn_radius: f32,
	#[serde(default)] pub ammo_count: AmmoCountIo,
	#[serde(default = "ammo_crate_supply_range_default")] pub ammo_crate_supply_range: (u32, u32),

	/**
	 * There is a fixed probability of an item spawning in a given update,
	 * independent of the previous spawned items, but proportional to the number
	 * of players.
	 *
	 * These variables here are the mean time period for an item to spawn. To
	 * derive the probability of an item spawning in an update, divide delta time
	 * by this and multiply it by the number of players in the game.
	 */
	#[serde(default = "ammo_crate_period_default")] pub ammo_crate_period: f32,
	#[serde(default = "powerup_period_default")] pub powerup_period: f32,

	/**
	 * When an item is spawned, a player is selected at random and the item is
	 * spawned within a square of this radius centred at that player.
	 */
	#[serde(default = "item_spawn_radius_default")] pub item_spawn_radius: f32,

	/**
	 * Players must not spawn less than this distance of ammo crates/powerups and
	 * vice versa.
	 *
	 * This prevents the player from getting surprised from the effects of an
	 * ammo crate/powerup, like the sound made or teleporting from a
	 * teleportation powerup.
	 */
	#[serde(default = "player_ammo_crate_spawn_separation_radius_default")] pub player_ammo_crate_spawn_separation_radius: f32,
	#[serde(default = "player_powerup_spawn_separation_radius_default")] pub player_powerup_spawn_separation_radius: f32,

	/**
	 * Specifies a list of effects that powerups are allowed to be.
	 *
	 * When a powerup is spawned, a randomly selected effect is chosen from this
	 * list, which means that if the list contains duplicates, those duplicates
	 * are weighted higher.
	 *
	 * If this list is empty, no powerups are ever spawned.
	 *
	 * By default this is the list of all effects.
	 */
	#[serde(default = "allowed_powerups_default")] pub allowed_powerups: Box<[PowerupType]>,
	#[serde(default)] pub effects: Effects,
}

impl Default for EventConfig {
	fn default() -> EventConfig {
		EventConfig {
			player_spawn_radius: player_spawn_radius_default(),
			ammo_count: AmmoCountIo::default(),
			ammo_crate_supply_range: ammo_crate_supply_range_default(),
			ammo_crate_period: ammo_crate_period_default(),
			powerup_period: powerup_period_default(),
			item_spawn_radius: item_spawn_radius_default(),
			player_ammo_crate_spawn_separation_radius: player_ammo_crate_spawn_separation_radius_default(),
			player_powerup_spawn_separation_radius: player_powerup_spawn_separation_radius_default(),
			allowed_powerups: allowed_powerups_default(),
			effects: Effects::default(),
		}
	}
}

fn ammo_crate_period_default() -> f32 { 30.0 }
fn item_spawn_radius_default() -> f32 { 40.0 }
fn player_ammo_crate_spawn_separation_radius_default() -> f32 { 4.0 }
fn player_powerup_spawn_separation_radius_default() -> f32 { 4.0 }
fn powerup_period_default() -> f32 { 60.0 }
fn player_spawn_radius_default() -> f32 { 32.0 }
fn ammo_crate_supply_range_default() -> (u32, u32) { (50, 75) }
fn allowed_powerups_default() -> Box<[PowerupType]> { PowerupType::iter().collect::<Box<_>>() }
