// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use crate::world::DELTA_TIME;

/**
 * A structure for a "clock" that is advanced by a continuous amount and
 * returns a discrete number of steps. This is mainly used for implementing a
 * fixed delta time in the world physics, but also used for particle effects.
 */
pub struct Clock {
	interval: f32,
	next_update: f32,
}

impl Clock {
	pub fn new(interval: f32) -> Clock { Clock { interval, next_update: 0.0 } }
	pub fn new_world() -> Clock { Clock::new(DELTA_TIME) }
	pub fn with_next_update(interval: f32, next_update: f32) -> Clock { Clock { interval, next_update } }

	/**
	 * Advances the internal clock and returns the appropriate number of physics
	 * steps to take.
	 */
	pub fn advance(&mut self, dt: f32) -> u32 {
		self.next_update -= dt;
		let updates = (1.0 - self.next_update / self.interval).floor(); // Updates when self.0 is ≤ 0
		if updates > 0.0 {
			self.next_update += updates * self.interval;
			updates as u32
		} else {
			0
		}
	}

	pub fn get_interval(&self) -> f32 {
		self.interval
	}

	/**
	 * Gets the difference to do frame interpolation between the updates.
	 *
	 * This code has the rendered world slightly lag behind the real world. The
	 * purpose of this is if it did the other way around of having things be
	 * ahead, when the extrapolation fails (like failing to predict a sudden
	 * change in keyboard input) you would get a bit of a jump in the player's
	 * position which doesn't look good.
	 *
	 * I could use this only for the player and not for bullets as the latter
	 * are very predictable, but I want to make things consistent as having
	 * inconsistent delays might make it slightly worse for players.
	 */
	#[cfg(feature = "client")]
	pub fn get_time_diff(&self) -> f32 {
		-self.next_update
	}

	pub fn set_next_update(&mut self, next_update: f32) {
		self.next_update = next_update;
	}
}
