pub struct SharedBuf {
    data: Vec<f32>,
    write_idx: usize,
    filled: bool,
}

impl SharedBuf {
    #[must_use]
    pub fn new(cap: usize) -> Self {
        Self {
            data: vec![0.0; cap],
            write_idx: 0,
            filled: false,
        }
    }

    #[inline]
    #[allow(clippy::arithmetic_side_effects)]
    pub fn push(&mut self, x: f32) {
        if let Some(v) = self.data.get_mut(self.write_idx) {
            *v = x;
        }
        let cap = self.data.len();
        if cap > 0 {
            let mask = cap - 1;
            self.write_idx = (self.write_idx + 1) & mask;
            if self.write_idx == 0 {
                self.filled = true;
            }
        }
    }

    #[inline]
    #[must_use]
    pub fn len(&self) -> usize {
        if self.filled {
            self.data.len()
        } else {
            self.write_idx
        }
    }

    #[inline]
    #[must_use]
    pub const fn is_empty(&self) -> bool {
        !self.filled && self.write_idx == 0
    }

    #[allow(clippy::arithmetic_side_effects)]
    pub fn copy_last_n_into(
        &self,
        n: usize,
        out: &mut Vec<f32>,
    ) -> bool {
        if n == 0 {
            out.clear();
            return true;
        }

        let cap = self.data.len();
        let len = self.len();
        if len < n {
            return false;
        }

        out.resize(n, 0.0);

        if self.filled {
            let start = (self.write_idx + cap - n) % cap;
            if start + n <= cap {
                if let Some(src) = self.data.get(start..start + n) {
                    out.copy_from_slice(src);
                }
            } else {
                let first = cap - start;
                if let Some(dst) = out.get_mut(..first) {
                    if let Some(src) = self.data.get(start..cap) {
                        dst.copy_from_slice(src);
                    }
                }
                if let Some(dst) = out.get_mut(first..) {
                    if let Some(src) = self.data.get(..(n - first)) {
                        dst.copy_from_slice(src);
                    }
                }
            }
        } else {
            let start = self.write_idx - n;
            if let Some(src) = self.data.get(start..self.write_idx) {
                out.copy_from_slice(src);
            }
        }

        true
    }

    #[must_use]
    pub fn latest(&self) -> Vec<f32> {
        let len = self.len();

        if len == 0 {
            return Vec::new();
        }

        let mut result = Vec::with_capacity(len);

        if self.filled {
            if let Some(src) = self.data.get(self.write_idx..) {
                result.extend_from_slice(src);
            }
            if let Some(src) = self.data.get(..self.write_idx) {
                result.extend_from_slice(src);
            }
        } else if let Some(src) = self.data.get(..self.write_idx) {
            result.extend_from_slice(src);
        }

        result
    }
}
