// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
pub mod blocks;

use std::{fs as sync_fs, path::Path};

use serde::{Deserialize, de::DeserializeOwned};
use tokio::fs as async_fs;

use crate::world::{player::{ammo_count::AmmoCount, config::MAX_HEALTH_DEFAULT}, effects::Effect};
use crate::utils::ron;

#[derive(Clone, Copy, Deserialize)]
#[serde(from = "f64", deny_unknown_fields /* Don't think it's needed */)]
pub struct AmmoCountIo(pub AmmoCount);

impl From<f64> for AmmoCountIo {
	fn from(count: f64) -> AmmoCountIo {
		AmmoCountIo(if count == f64::INFINITY {
			AmmoCount::new_infinite()
		} else {
			AmmoCount::new(count as u32)
		})
	}
}

impl Default for AmmoCountIo {
	fn default() -> AmmoCountIo {
		AmmoCountIo(AmmoCount::new(100))
	}
}

#[derive(Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Effects {
	#[serde(default = "effect_time_default")] pub effect_time: f32,
	#[serde(default)] pub powerup_effect_reduction: EffectReduction,
	#[serde(default = "speed_mul_default")] pub speed_mul: f32,
	#[serde(default = "other_effect_power_default")] pub reload_mul: f32,
	#[serde(default = "regen_mul_default")] pub regen_mul: f32,
	#[serde(default = "other_effect_power_default")] pub damage_mul: f32,
	#[serde(default = "forcefield_strength_default")] pub forcefield_strength: f32,
	#[serde(default = "health_powerup_health_increase_default")] pub health_powerup_health_increase: f32,
}

impl Default for Effects {
	fn default() -> Effects {
		Effects {
			effect_time: effect_time_default(),
			powerup_effect_reduction: EffectReduction::default(),
			speed_mul: speed_mul_default(),
			reload_mul: other_effect_power_default(),
			regen_mul: regen_mul_default(),
			damage_mul: other_effect_power_default(),
			forcefield_strength: forcefield_strength_default(),
			health_powerup_health_increase: health_powerup_health_increase_default(),
		}
	}
}

fn effect_time_default() -> f32 { 30.0 }
fn speed_mul_default() -> f32 { 1.375 }
fn regen_mul_default() -> f32 { 2.0 }
fn forcefield_strength_default() -> f32 { 250.0 }
fn other_effect_power_default() -> f32 { 1.5 }
fn health_powerup_health_increase_default() -> f32 { MAX_HEALTH_DEFAULT * 0.5 }

impl Effects {
	pub fn get_effect_power(&self, effect: Effect) -> f32 {
		match effect {
			Effect::Speed => self.speed_mul,
			Effect::Reload => self.reload_mul,
			Effect::Regeneration => self.regen_mul,
			Effect::Damage => self.damage_mul,
			Effect::Forcefield => self.forcefield_strength,
		}
	}
}

#[derive(Default, Clone, Copy, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum EffectReduction {
	Extend, // Increases the duration
	#[default] Stack, // Increase the power when two of the same effects overlap
}

fn deserialise<C: DeserializeOwned>(data: Vec<u8>) -> Result<C, String> {
	ron::deserialise(&data).map_err(|err| format!("invalid config file: {err}"))
}

pub fn load_sync<C: DeserializeOwned>(path: &Path) -> Result<C, String> {
	deserialise(sync_fs::read(path).map_err(|err| format!("cannot read file \"{}\": {err}", path.display()))?)
}

pub async fn load_async<C: DeserializeOwned>(path: &Path) -> Result<C, String> {
	deserialise(async_fs::read(path).await.map_err(|err| format!("cannot read file \"{}\": {err}", path.display()))?)
}
