/// Collects tap timestamps and calculates tempo when enough taps are received.
#[derive(Debug)]
pub struct TapTempo {
    sample_rate: usize,
    tap_times: [u32; Self::MAX_TAPS],
    tap_count: usize,
}

impl TapTempo {
    const MAX_TAPS: usize = 8;
    const MIN_TAPS: usize = 4;
    const MIN_INTERVAL_MS: usize = 100;
    const MAX_INTERVAL_MS: usize = 2000;

    pub fn new(sample_rate: usize) -> Self {
        Self {
            sample_rate,
            tap_times: [0; Self::MAX_TAPS],
            tap_count: 0,
        }
    }

    pub fn handle_tap(&mut self, current_frame_time: u32) -> Option<usize> {
        self.record_tap(current_frame_time);
        self.calculate_tempo()
    }

    fn record_tap(&mut self, frame_time: u32) {
        // Check if valid interval range
        if self.tap_count > 0 {
            let last_tap = self.tap_times[self.tap_count - 1];
            if frame_time - last_tap < (Self::MIN_INTERVAL_MS * self.sample_rate / 1000) as u32 {
                return;
            }
            if frame_time - last_tap > (Self::MAX_INTERVAL_MS * self.sample_rate / 1000) as u32 {
                self.tap_count = 0;
            }
        }
        // Add new entry
        if self.tap_count < Self::MAX_TAPS {
            self.tap_times[self.tap_count] = frame_time;
            self.tap_count += 1;
        } else {
            self.tap_times[0] = frame_time;
            self.tap_times.rotate_left(1);
        }
    }

    fn calculate_tempo(&self) -> Option<usize> {
        if self.tap_count < Self::MIN_TAPS {
            return None;
        }

        let mut total_interval = 0u64;
        let interval_count = self.tap_count - 1;

        for i in 1..self.tap_count {
            let interval = self.tap_times[i] - self.tap_times[i - 1];
            total_interval += interval as u64;
        }

        let average_interval = (total_interval / interval_count as u64) as usize;
        Some(average_interval)
    }
}
