use crate::{
    N_INF,
    drift::{ConstantDrift, Drift},
    gaussian::Gaussian,
    rating::Rating,
    time::Time,
};

/// Per-history, temporal state for someone competing.
///
/// Renamed from `Agent` in T2; the former `.player` field is now
/// `.rating` to match the `Player → Rating` rename.
#[derive(Debug)]
pub struct Competitor<T: Time = i64, D: Drift<T> = ConstantDrift> {
    pub rating: Rating<T, D>,
    pub message: Gaussian,
    pub last_time: Option<T>,
}

impl<T: Time, D: Drift<T>> Competitor<T, D> {
    /// Compute the message received at time `now`, with drift accumulated
    /// from `self.last_time` (if any) to `now`.
    pub(crate) fn receive(&self, now: &T) -> Gaussian {
        if self.message != N_INF {
            let elapsed_variance = match &self.last_time {
                Some(last) => self.rating.drift.variance_delta(last, now),
                None => 0.0,
            };
            self.message.forget(elapsed_variance)
        } else {
            self.rating.prior
        }
    }

    /// Compute the message using a pre-cached elapsed count (in `Time::elapsed_to` units).
    ///
    /// Used in convergence sweeps where the elapsed was cached at slice-construction time
    /// and should not be recomputed from `last_time` (which may have shifted).
    pub(crate) fn receive_for_elapsed(&self, elapsed: i64) -> Gaussian {
        if self.message != N_INF {
            self.message
                .forget(self.rating.drift.variance_for_elapsed(elapsed))
        } else {
            self.rating.prior
        }
    }
}

impl Default for Competitor<i64, ConstantDrift> {
    fn default() -> Self {
        Self {
            rating: Rating::default(),
            message: N_INF,
            last_time: None,
        }
    }
}

pub(crate) fn clean<'a, T, D, C>(competitors: C, last_time: bool)
where
    T: Time + 'a,
    D: Drift<T> + 'a,
    C: Iterator<Item = &'a mut Competitor<T, D>>,
{
    for c in competitors {
        c.message = N_INF;
        if last_time {
            c.last_time = None;
        }
    }
}
