use jam_tooling::format::concise_duration;
use jam_types::VecMap;
use std::time::{Duration, Instant};

/// Lightweight timer for bucket-based performance benchmarking.
pub struct Timer {
	t: Instant,
	stats: VecMap<&'static str, Duration>,
}

impl Timer {
	pub fn new() -> Self {
		Self { t: Instant::now(), stats: VecMap::new() }
	}

	/// Add duration since the last call to [`Self::add`] or [`Self::new`] to the bucket `name`.
	pub fn add(&mut self, name: &'static str) {
		let now = Instant::now();
		let dt = now.checked_duration_since(self.t).unwrap_or(Duration::ZERO);
		match self.stats.get_mut(name) {
			Some(counter) => *counter += dt,
			None => {
				self.stats.insert(name, dt);
			},
		}
		self.t = now;
	}

	/// Get total duration of all buckets.
	pub fn total(&self) -> Duration {
		let mut sum = Duration::ZERO;
		for dt in self.stats.values().copied() {
			sum += dt;
		}
		sum
	}
}

impl std::fmt::Display for Timer {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		let mut iter = self.stats.iter();
		if let Some((name, dt)) = iter.next() {
			write!(f, "{name} ({})", concise_duration(*dt))?;
		}
		for (name, dt) in iter {
			write!(f, ", {name} ({})", concise_duration(*dt))?;
		}
		Ok(())
	}
}
