// Audio operations for WAV audio data

///|
/// Trim audio samples to a specified range.
///
/// # Arguments
/// * `samples` - Input audio samples
/// * `start_sample` - Start index (inclusive)
/// * `end_sample` - End index (exclusive)
///
/// # Returns
/// * `Array[Int]` - Trimmed samples
pub fn trim(
  samples : Array[Int],
  start_sample : Int,
  end_sample : Int,
) -> Array[Int] {
  let result = []
  let actual_end = if end_sample > samples.length() {
    samples.length()
  } else {
    end_sample
  }
  let actual_start = if start_sample < 0 { 0 } else { start_sample }

  let mut i = actual_start
  while i < actual_end {
    result.push(samples[i])
    i = i + 1
  }

  result
}

///|
/// Concatenate two audio sample arrays.
///
/// # Arguments
/// * `a` - First audio samples
/// * `b` - Second audio samples
///
/// # Returns
/// * `Array[Int]` - Concatenated samples
pub fn concat(a : Array[Int], b : Array[Int]) -> Array[Int] {
  let result = []
  let mut i = 0
  while i < a.length() {
    result.push(a[i])
    i = i + 1
  }
  i = 0
  while i < b.length() {
    result.push(b[i])
    i = i + 1
  }
  result
}

///|
/// Adjust the volume of audio samples.
///
/// # Arguments
/// * `samples` - Input audio samples
/// * `factor` - Volume multiplier (1.0 = no change, 0.5 = half volume, 2.0 = double)
///
/// # Returns
/// * `Array[Int]` - Volume-adjusted samples
pub fn adjust_volume(samples : Array[Int], factor : Double) -> Array[Int] {
  let result = []
  let mut i = 0
  while i < samples.length() {
    let adjusted = (Double::from_int(samples[i]) * factor).to_int()
    result.push(adjusted)
    i = i + 1
  }
  result
}

///|
/// Mix two audio streams together by averaging.
///
/// # Arguments
/// * `a` - First audio samples
/// * `b` - Second audio samples
///
/// # Returns
/// * `Array[Int]` - Mixed samples (length = max(a.length, b.length))
pub fn mix(a : Array[Int], b : Array[Int]) -> Array[Int] {
  let result = []
  let max_len = if a.length() > b.length() { a.length() } else { b.length() }

  let mut i = 0
  while i < max_len {
    let sample_a = if i < a.length() { a[i] } else { 0 }
    let sample_b = if i < b.length() { b[i] } else { 0 }
    let mixed = (sample_a + sample_b) / 2
    result.push(mixed)
    i = i + 1
  }

  result
}

///|
/// Fade in audio samples.
///
/// # Arguments
/// * `samples` - Input audio samples
/// * `fade_samples` - Number of samples to fade in
///
/// # Returns
/// * `Array[Int]` - Samples with fade in applied
pub fn fade_in(samples : Array[Int], fade_samples : Int) -> Array[Int] {
  let result = []
  let fade_len = if fade_samples > samples.length() {
    samples.length()
  } else {
    fade_samples
  }

  let mut i = 0
  while i < samples.length() {
    if i < fade_len {
      let factor = Double::from_int(i) / Double::from_int(fade_len)
      let faded = (Double::from_int(samples[i]) * factor).to_int()
      result.push(faded)
    } else {
      result.push(samples[i])
    }
    i = i + 1
  }

  result
}

///|
/// Fade out audio samples.
///
/// # Arguments
/// * `samples` - Input audio samples
/// * `fade_samples` - Number of samples to fade out
///
/// # Returns
/// * `Array[Int]` - Samples with fade out applied
pub fn fade_out(samples : Array[Int], fade_samples : Int) -> Array[Int] {
  let result = []
  let fade_len = if fade_samples > samples.length() {
    samples.length()
  } else {
    fade_samples
  }
  let fade_start = samples.length() - fade_len

  let mut i = 0
  while i < samples.length() {
    if i >= fade_start {
      let factor = Double::from_int(samples.length() - 1 - i) /
        Double::from_int(fade_len)
      let faded = (Double::from_int(samples[i]) * factor).to_int()
      result.push(faded)
    } else {
      result.push(samples[i])
    }
    i = i + 1
  }

  result
}

///|
/// Reverse audio samples.
///
/// # Arguments
/// * `samples` - Input audio samples
///
/// # Returns
/// * `Array[Int]` - Reversed samples
pub fn reverse(samples : Array[Int]) -> Array[Int] {
  let result = []
  let len = samples.length()

  let mut i = 0
  while i < len {
    result.push(samples[len - 1 - i])
    i = i + 1
  }

  result
}

///|
/// Get the peak amplitude of audio samples.
///
/// # Arguments
/// * `samples` - Input audio samples
///
/// # Returns
/// * `Int` - Peak amplitude (absolute value)
pub fn get_peak_amplitude(samples : Array[Int]) -> Int {
  let mut peak = 0
  let mut i = 0
  while i < samples.length() {
    let abs_sample = if samples[i] < 0 { -samples[i] } else { samples[i] }
    if abs_sample > peak {
      peak = abs_sample
    }
    i = i + 1
  }
  peak
}

///|
/// Get the RMS (Root Mean Square) level of audio samples.
///
/// # Arguments
/// * `samples` - Input audio samples
///
/// # Returns
/// * `Double` - RMS level
pub fn get_rms_level(samples : Array[Int]) -> Double {
  if samples.length() == 0 {
    return 0.0
  }

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

  let mean = sum_squares / Double::from_int(samples.length())
  mean.sqrt()
}