// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use serde::{Serialize, Deserialize};
use strum_macros::{EnumCount, EnumIter, IntoStaticStr};
use glam::Vec2;

use super::effects::Effect;

use crate::utils::maths::Circle;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumCount, EnumIter, IntoStaticStr)]
pub enum PowerupType {
	Speed,
	Reload,
	Health,
	Damage,
	Forcefield,
	Teleportation,
}

impl From<Effect> for PowerupType {
	fn from(effect: Effect) -> PowerupType {
		match effect {
			Effect::Speed => PowerupType::Speed,
			Effect::Reload => PowerupType::Reload,
			Effect::Regeneration => PowerupType::Health,
			Effect::Damage => PowerupType::Damage,
			Effect::Forcefield => PowerupType::Forcefield,
		}
	}
}

pub const RADIUS: f32 = 1.0 / 3.0;
const FADE_IN_TIME: f32 = 1.0;
const FADE_OUT_TIME: f32 = 30.0;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Powerup {
	pos: Vec2,
	scale: f32,
	time: f32,
	max_time: f32,
	typ: PowerupType,
}

impl Powerup {
	pub fn new(pos: Vec2, typ: PowerupType, max_time: f32) -> Powerup {
		Powerup { pos, scale: 0.0, time: 0.0, max_time, typ }
	}

	pub fn get_type(&self) -> PowerupType { self.typ }
	#[cfg(feature = "client")] pub fn get_time(&self) -> f32 { self.time }
	#[cfg(feature = "client")] pub fn get_max_time(&self) -> f32 { self.max_time }

	pub fn update(&mut self, dt: f32) -> bool {
		self.time += dt;
		self.scale = Powerup::get_scale(self.time, self.max_time);
		self.time <= self.max_time
	}

	pub fn get_scale(time: f32, max_time: f32) -> f32 {
		if time < FADE_IN_TIME {
			let f = time / FADE_IN_TIME;
			f * (2.0 - f)
		} else if time > max_time - FADE_OUT_TIME {
			let f = (max_time - time) / FADE_OUT_TIME;
			f * (2.0 - f)
		} else {
			1.0
		}
	}
}

impl Circle for Powerup {
	fn get_pos(&self) -> Vec2 { self.pos }
	fn get_radius(&self) -> f32 { RADIUS * self.scale }
}
