///|
/// A detached point-in-time view of a streaming loudness analyzer.
pub struct MeterSnapshot {
  priv sample_rate : Int32
  priv frame_count : Int32
  priv sample_count : Int32
  priv momentary_lufs : Double?
  priv short_term_lufs : Double?
  priv sample_peak_linear : Double
  priv true_peak_linear : Double
  priv channel_sample_peaks_linear : Array[Double]
}

///|
/// Returns the frame position represented by this snapshot.
pub fn MeterSnapshot::sample_rate(self : MeterSnapshot) -> Int32 {
  self.sample_rate
}

///|
pub fn MeterSnapshot::frame_count(self : MeterSnapshot) -> Int32 {
  self.frame_count
}

///|
pub fn MeterSnapshot::duration_seconds(self : MeterSnapshot) -> Double {
  self.frame_count.to_double() / self.sample_rate.to_double()
}

///|
pub fn MeterSnapshot::sample_count(self : MeterSnapshot) -> Int32 {
  self.sample_count
}

///|
pub fn MeterSnapshot::momentary_lufs(self : MeterSnapshot) -> Double? {
  self.momentary_lufs
}

///|
pub fn MeterSnapshot::short_term_lufs(self : MeterSnapshot) -> Double? {
  self.short_term_lufs
}

///|
pub fn MeterSnapshot::sample_peak_linear(self : MeterSnapshot) -> Double {
  self.sample_peak_linear
}

///|
pub fn MeterSnapshot::true_peak_linear(self : MeterSnapshot) -> Double {
  self.true_peak_linear
}

///|
/// Returns channel peaks in the configured layout order as an independent array.
pub fn MeterSnapshot::channel_sample_peaks_linear(
  self : MeterSnapshot,
) -> Array[Double] {
  let result : Array[Double] = []
  for peak in self.channel_sample_peaks_linear {
    result.push(peak)
  }
  result
}

///|
/// Bounded chronological history of measurements emitted by one analyzer.
priv struct MeasurementHistory {
  capacity : Int32
  values : Array[MeterSnapshot]
  mut next : Int32
  mut count : Int32
}

///|
fn MeasurementHistory::new(capacity : Int32) -> MeasurementHistory {
  let values : Array[MeterSnapshot] = []
  for _ in 0.. Unit {
  if self.capacity > 0 {
    self.values[self.next] = point
    self.next = (self.next + 1) % self.capacity
    if self.count < self.capacity {
      self.count = self.count + 1
    }
  }
}

///|
fn MeasurementHistory::points(
  self : MeasurementHistory,
) -> Array[MeterSnapshot] {
  let result : Array[MeterSnapshot] = []
  let start = if self.count == self.capacity { self.next } else { 0 }
  for offset in 0.. Int32? {
  if self.count == 0 {
    None
  } else {
    let index = (self.next + self.capacity - 1) % self.capacity
    Some(self.values[index].frame_count)
  }
}

///|
fn MeasurementHistory::clear(self : MeasurementHistory) -> Unit {
  self.next = 0
  self.count = 0
}

///|
/// Returns the current counters, levels, and peaks without changing analyzer state.
pub fn Analyzer::snapshot(self : Analyzer) -> MeterSnapshot {
  {
    sample_rate: self.config.sample_rate,
    frame_count: self.frame_count,
    sample_count: self.sample_count,
    momentary_lufs: self.momentary_lufs(),
    short_term_lufs: self.short_term_lufs(),
    sample_peak_linear: self.sample_peak,
    true_peak_linear: self.true_peak_linear(),
    channel_sample_peaks_linear: self.channel_sample_peaks_linear(),
  }
}

///|
/// Returns retained measurement points in chronological order.
pub fn Analyzer::history(self : Analyzer) -> Array[MeterSnapshot] {
  self.history.points()
}

///|
/// Returns the configured maximum number of retained points.
pub fn Analyzer::history_capacity(self : Analyzer) -> Int32 {
  self.history.capacity
}

///|
/// Drops historical points while keeping all live measurement state.
pub fn Analyzer::clear_history(self : Analyzer) -> Unit {
  self.history.clear()
}

///|
fn Analyzer::record_snapshot(self : Analyzer) -> Unit {
  self.history.push(self.snapshot())
}

///|
/// Returns snapshot sample peak in dBFS, or None for digital silence.
pub fn MeterSnapshot::sample_peak_dbfs(self : MeterSnapshot) -> Double? {
  amplitude_to_db(self.sample_peak_linear)
}

///|
/// Returns the live FIR estimate in dBTP, or None for digital silence.
pub fn MeterSnapshot::true_peak_dbtp(self : MeterSnapshot) -> Double? {
  amplitude_to_db(self.true_peak_linear)
}

///|
// Replace a terminal point after FIR tail flushing without adding a second timestamp.
fn MeasurementHistory::replace_last(
  self : MeasurementHistory,
  point : MeterSnapshot,
) -> Unit {
  if self.count > 0 {
    let index = (self.next + self.capacity - 1) % self.capacity
    self.values[index] = point
  }
}