pub struct RingBuffer<T: Copy + Default> {
    pub data: Vec<T>,

    // Index to next writing element
    pub head: usize,

    // Actual size
    pub size: usize,

    pub capacity: usize,
}

impl<T: Copy + Default> RingBuffer<T> {
    pub fn new(capacity: usize) -> Self {
        assert!(capacity != 0);
        Self {
            data: vec![T::default(); capacity],
            head: 0,
            size: 0,
            capacity,
        }
    }

    pub fn push(&mut self, value: T) {
        self.data[self.head] = value;
        self.head = (self.head + 1) % self.capacity;
        self.size = (self.size + 1).min(self.capacity);
    }

    pub fn pop(&mut self) -> Option<T> {
        if self.size == 0 {
            return None;
        }
        let tail = (self.head + self.capacity - self.size) % self.capacity;
        self.size -= 1;
        Some(self.data[tail])
    }

    pub fn peek(&self) -> Option<&T> {
        if self.size == 0 {
            return None;
        }
        let last = (self.head + self.capacity - 1) % self.capacity;
        Some(&self.data[last])
    }

    // Read N samples before
    pub fn read_at(&self, delay: usize) -> Option<&T> {
        if delay >= self.size {
            return None;
        }
        let index = (self.head + self.capacity - 1 - delay) % self.capacity;
        Some(&self.data[index])
    }

    pub fn write_read(&mut self, value: T, delay: usize) -> Option<T> {
        let delayed = self.read_at(delay).copied();
        self.push(value);
        delayed
    }

    pub fn len(&self) -> usize {
        self.size
    }

    pub fn is_empty(&self) -> bool {
        self.size == 0
    }

    pub fn is_full(&self) -> bool {
        self.size == self.capacity
    }

    pub fn clear(&mut self) {
        self.head = 0;
        self.size = 0;
    }
}
