// Audio analysis functions

///|
/// Result of audio analysis.
pub struct AudioAnalysis {
  /// Duration in seconds
  duration_sec : Double
  /// Number of samples per channel
  samples_per_channel : Int
  /// Peak amplitude (absolute value)
  peak : Int
  /// RMS level
  rms : Double
  /// DC offset (mean value)
  dc_offset : Double
  /// Number of zero crossings
  zero_crossings : Int
  /// Whether clipping was detected
  has_clipping : Bool
  /// Number of clipped samples
  clipped_samples : Int
  /// Whether silence was detected (below threshold)
  is_silent : Bool
  /// Ratio of silent samples (0.0 to 1.0)
  silence_ratio : Double
} derive(Debug)

///|
/// Analyze audio samples and return comprehensive statistics.
///
/// # Arguments
/// * `audio` - The audio data to analyze
/// * `silence_threshold` - Amplitude threshold below which is considered silent (default: 100)
///
/// # Returns
/// * `AudioAnalysis` - Comprehensive analysis result
pub fn analyze(audio : AudioData, silence_threshold : Int) -> AudioAnalysis {
  let samples = audio.samples
  let info = audio.info

  let duration_sec = Double::from_int(info.data_size) /
    Double::from_int(info.byte_rate)
  let samples_per_channel = if info.num_channels > 0 {
    samples.length() / info.num_channels
  } else {
    samples.length()
  }

  // Peak amplitude
  let peak = get_peak_amplitude(samples)

  // RMS level
  let rms = get_rms_level(samples)

  // DC offset (mean)
  let dc_offset = calculate_dc_offset(samples)

  // Zero crossings
  let zero_crossings = count_zero_crossings(samples)

  // Clipping detection
  let max_val = match info.bits_per_sample {
    8 => 127
    16 => 32767
    24 => 8388607
    32 => 2147483647
    _ => 32767
  }
  let min_val = -max_val - 1
  let clipped = count_clipped_samples(samples, min_val, max_val)
  let has_clipping = clipped > 0

  // Silence detection
  let silent_count = count_silent_samples(samples, silence_threshold)
  let silence_ratio = if samples.length() > 0 {
    Double::from_int(silent_count) / Double::from_int(samples.length())
  } else {
    1.0
  }
  let is_silent = silence_ratio > 0.95

  {
    duration_sec,
    samples_per_channel,
    peak,
    rms,
    dc_offset,
    zero_crossings,
    has_clipping,
    clipped_samples: clipped,
    is_silent,
    silence_ratio,
  }
}

///|
/// Calculate the DC offset (mean value) of audio samples.
pub fn calculate_dc_offset(samples : Array[Int]) -> Double {
  if samples.length() == 0 {
    return 0.0
  }

  let mut sum = 0.0
  let mut i = 0
  while i < samples.length() {
    sum = sum + Double::from_int(samples[i])
    i = i + 1
  }
  sum / Double::from_int(samples.length())
}

///|
/// Count the number of zero crossings in the audio signal.
/// A zero crossing occurs when consecutive samples have different signs.
pub fn count_zero_crossings(samples : Array[Int]) -> Int {
  let mut count = 0
  let mut i = 1
  while i < samples.length() {
    if (samples[i - 1] >= 0 && samples[i] < 0) ||
      (samples[i - 1] < 0 && samples[i] >= 0) {
      count = count + 1
    }
    i = i + 1
  }
  count
}

///|
/// Count the number of clipped samples (at min or max value).
pub fn count_clipped_samples(
  samples : Array[Int],
  min_val : Int,
  max_val : Int,
) -> Int {
  let mut count = 0
  let mut i = 0
  while i < samples.length() {
    if samples[i] <= min_val || samples[i] >= max_val {
      count = count + 1
    }
    i = i + 1
  }
  count
}

///|
/// Count the number of silent samples (absolute value below threshold).
pub fn count_silent_samples(
  samples : Array[Int],
  threshold : Int,
) -> Int {
  let mut count = 0
  let mut i = 0
  while i < samples.length() {
    let abs_val = if samples[i] < 0 { -samples[i] } else { samples[i] }
    if abs_val < threshold {
      count = count + 1
    }
    i = i + 1
  }
  count
}

///|
/// Format audio analysis as a human-readable string.
pub fn format_analysis(analysis : AudioAnalysis) -> String {
  let lines = []
  lines.push("=== Audio Analysis ===")
  lines.push("Duration: " + analysis.duration_sec.to_string() + " seconds")
  lines.push("Samples per channel: " + analysis.samples_per_channel.to_string())
  lines.push("Peak amplitude: " + analysis.peak.to_string())
  lines.push("RMS level: " + analysis.rms.to_string())
  lines.push("DC offset: " + analysis.dc_offset.to_string())
  lines.push("Zero crossings: " + analysis.zero_crossings.to_string())
  lines.push(
    "Clipping: " + (if analysis.has_clipping { "YES (" + analysis.clipped_samples.to_string() + " samples)" } else { "No" }),
  )
  lines.push(
    "Silence: " + (if analysis.is_silent { "YES" } else { "No" }) +
      " (" + (analysis.silence_ratio * 100.0).to_string() + "%)",
  )

  // Concatenate all lines
  let mut result = ""
  let mut i = 0
  while i < lines.length() {
    if i > 0 {
      result = result + "\n"
    }
    result = result + lines[i]
    i = i + 1
  }
  result
}