///|
fn abs_double(value : Double) -> Double {
  if value < 0.0 {
    -value
  } else {
    value
  }
}

///|
fn max_double(a : Double, b : Double) -> Double {
  if a >= b {
    a
  } else {
    b
  }
}

///|
fn min_double(a : Double, b : Double) -> Double {
  if a <= b {
    a
  } else {
    b
  }
}

///|
pub fn analyze_audio(buffer : FloatBuffer) -> AudioStats {
  if !buffer.is_valid() || buffer.samples.length() == 0 {
    AudioStats::empty()
  } else {
    let total = buffer.samples.length()
    let peak = for sample in buffer.samples; value = 0.0 {
      continue max_double(value, abs_double(sample))
    } nobreak {
      value
    }
    let sum = for sample in buffer.samples; value = 0.0 {
      continue value + sample
    } nobreak {
      value
    }
    let sum_sq = for sample in buffer.samples; value = 0.0 {
      continue value + sample * sample
    } nobreak {
      value
    }
    let silent = for sample in buffer.samples; count = 0 {
      if abs_double(sample) <= 0.0001 {
        continue count + 1
      } else {
        continue count
      }
    } nobreak {
      count
    }
    let clipped = for sample in buffer.samples; count = 0 {
      if abs_double(sample) >= 0.999 {
        continue count + 1
      } else {
        continue count
      }
    } nobreak {
      count
    }
    {
      duration_seconds: buffer.duration_seconds(),
      frame_count: buffer.frame_count(),
      sample_count: total,
      peak,
      rms: (sum_sq / total.to_double()).sqrt(),
      silent_samples: silent,
      clipped_samples: clipped,
      dc_offset: sum / total.to_double(),
    }
  }
}

///|
pub fn summarize_waveform(
  buffer : FloatBuffer,
  buckets : Int,
) -> WaveformSummary {
  if !buffer.is_valid() || buckets <= 0 || buffer.samples.length() == 0 {
    WaveformSummary::empty()
  } else {
    let source_samples = buffer.samples.length()
    let safe_buckets = if buckets > source_samples {
      source_samples
    } else {
      buckets
    }
    let bucket_values = Array::makei(safe_buckets, bucket_index => {
      let start = bucket_index * source_samples / safe_buckets
      let end = (bucket_index + 1) * source_samples / safe_buckets
      let real_end = if end <= start { start + 1 } else { end }
      let min_value = for i in start.. Array[WaveChunk] {
  if !buffer.is_valid() || min_run <= 0 {
    []
  } else {
    let regions : Array[WaveChunk] = []
    let mut start = -1
    for i in 0..= 0 {
        let len = i - start
        if len >= min_run {
          regions.push(WaveChunk::new("silence", start, start, len))
        }
        start = -1
      }
    }
    if start >= 0 {
      let len = buffer.samples.length() - start
      if len >= min_run {
        regions.push(WaveChunk::new("silence", start, start, len))
      }
    }
    regions
  }
}

///|
pub fn stats_quality_label(stats : AudioStats) -> String {
  if stats.sample_count == 0 {
    "empty"
  } else if stats.has_clipping() {
    "clipped"
  } else if stats.peak < 0.02 {
    "very-quiet"
  } else if stats.silence_ratio() > 0.95 {
    "mostly-silent"
  } else {
    "ok"
  }
}