use std::time::{Duration, Instant};

pub struct Metronome {
    taps: Vec<Instant>,
    beat_interval: Option<u128>,
    timeout: Duration,
}

impl Metronome {
    pub fn new(timeout: Duration) -> Self {
        Self {
            taps: Vec::new(),
            beat_interval: None,
            timeout,
        }
    }

    pub fn tap(&mut self) {
        let now = Instant::now();
        if let Some(t) = self.taps.last() {
            if now - *t > self.timeout {
                self.taps.clear();
                self.beat_interval = None;
            }
        }

        self.taps.push(now);

        let n = self.taps.len();
        if n >= 2 {
            let dt = *self.taps.last().unwrap() - *self.taps.first().unwrap();
            let interval_millis = dt.as_millis() / (n - 1) as u128;
            self.beat_interval = Some(interval_millis);
        }
    }

    pub fn current_beat_progress(&self) -> Option<f64> {
        if self.beat_interval.is_none() {
            return None;
        }

        let now = Instant::now();
        let relative_millis = (now - *self.taps.last().unwrap()).as_millis();

        Some(relative_millis as f64 / self.beat_interval.unwrap() as f64)
    }
}
