use std::fmt::Debug;

use crate::time::Time;

/// Governs how much a competitor's skill can drift between two time points.
///
/// Generic over `T: Time` so seasonal or calendar-aware drift is expressible
/// without going through `i64`.
pub trait Drift<T: Time>: Copy + Debug + Send + Sync {
    /// Variance added to the skill prior for elapsed time `from -> to`.
    ///
    /// Called with `from <= to`; returning zero means no drift accumulates.
    fn variance_delta(&self, from: &T, to: &T) -> f64;

    /// Variance added for a pre-computed elapsed count (in the same units as
    /// `T::elapsed_to`). Used where the elapsed is already cached as `i64`.
    fn variance_for_elapsed(&self, elapsed: i64) -> f64;
}

/// Simple constant-per-unit-time drift.
///
/// For `Time = i64`: variance added is `(to - from) * gamma^2`.
/// For `Time = Untimed`: elapsed is always 0, so drift is always 0.
#[derive(Clone, Copy, Debug)]
pub struct ConstantDrift(pub f64);

impl<T: Time> Drift<T> for ConstantDrift {
    fn variance_delta(&self, from: &T, to: &T) -> f64 {
        let elapsed = from.elapsed_to(to).max(0) as f64;
        elapsed * self.0 * self.0
    }

    fn variance_for_elapsed(&self, elapsed: i64) -> f64 {
        elapsed.max(0) as f64 * self.0 * self.0
    }
}
