// WAV encoder - write audio data to WAV file format

///|
/// Encode audio samples and format info into a WAV file.
///
/// # Arguments
/// * `audio` - The audio data to encode
///
/// # Returns
/// * `Bytes` - The encoded WAV file bytes
pub fn encode(audio : AudioData) -> Bytes {
  let info = audio.info
  let samples = audio.samples
  let bytes_per_sample = info.bits_per_sample / 8
  let data_size = samples.length() * bytes_per_sample
  let file_size = 36 + data_size

  let buf = Buffer(size_hint=file_size + 12)

  // RIFF header
  buf.write_bytes(b"RIFF")
  buf.write_int_le(file_size)
  buf.write_bytes(b"WAVE")

  // fmt chunk
  buf.write_bytes(b"fmt ")
  buf.write_int_le(16) // chunk size
  buf.write_int16_le(Int16::from_int(info.audio_format))
  buf.write_int16_le(Int16::from_int(info.num_channels))
  buf.write_int_le(info.sample_rate)
  buf.write_int_le(info.byte_rate)
  buf.write_int16_le(Int16::from_int(info.block_align))
  buf.write_int16_le(Int16::from_int(info.bits_per_sample))

  // data chunk
  buf.write_bytes(b"data")
  buf.write_int_le(data_size)

  // Encode samples based on bit depth
  match info.bits_per_sample {
    8 => encode_samples_8bit(buf, samples)
    16 => encode_samples_16bit(buf, samples)
    24 => encode_samples_24bit(buf, samples)
    32 => encode_samples_32bit(buf, samples)
    _ => () // Should not happen with valid WavInfo
  }

  buf.to_bytes()
}

///|
/// Encode audio samples into a WAV file with specified format.
///
/// # Arguments
/// * `samples` - The audio samples
/// * `num_channels` - Number of channels (1 or 2)
/// * `sample_rate` - Sample rate in Hz
/// * `bits_per_sample` - Bit depth (8, 16, 24, or 32)
///
/// # Returns
/// * `Bytes` - The encoded WAV file bytes
pub fn encode_with_format(
  samples : Array[Int],
  num_channels : Int,
  sample_rate : Int,
  bits_per_sample : Int,
) -> Bytes {
  let bytes_per_sample = bits_per_sample / 8
  let byte_rate = sample_rate * num_channels * bytes_per_sample
  let block_align = num_channels * bytes_per_sample

  let info : WavInfo = {
    audio_format: 1,
    num_channels,
    sample_rate,
    byte_rate,
    block_align,
    bits_per_sample,
    data_size: samples.length() * bytes_per_sample,
  }

  encode({ samples, info })
}

///|
/// Encode 8-bit PCM samples (unsigned, centered at 128).
fn encode_samples_8bit(buf : Buffer, samples : Array[Int]) -> Unit {
  let mut i = 0
  while i < samples.length() {
    // Convert signed to unsigned: add 128, clamp to [0, 255]
    let val = samples[i] + 128
    let clamped = if val < 0 { 0 } else if val > 255 { 255 } else { val }
    buf.write_byte(clamped.to_byte())
    i = i + 1
  }
}

///|
/// Encode 16-bit PCM samples (signed, little-endian).
fn encode_samples_16bit(buf : Buffer, samples : Array[Int]) -> Unit {
  let mut i = 0
  while i < samples.length() {
    let clamped = if samples[i] < -32768 {
      -32768
    } else if samples[i] > 32767 {
      32767
    } else {
      samples[i]
    }
    buf.write_int16_le(Int16::from_int(clamped))
    i = i + 1
  }
}

///|
/// Encode 24-bit PCM samples (signed, little-endian).
fn encode_samples_24bit(buf : Buffer, samples : Array[Int]) -> Unit {
  let mut i = 0
  while i < samples.length() {
    let clamped = if samples[i] < -8388608 {
      -8388608
    } else if samples[i] > 8388607 {
      8388607
    } else {
      samples[i]
    }
    buf.write_byte((clamped & 0xFF).to_byte())
    buf.write_byte(((clamped >> 8) & 0xFF).to_byte())
    buf.write_byte(((clamped >> 16) & 0xFF).to_byte())
    i = i + 1
  }
}

///|
/// Encode 32-bit PCM samples (signed, little-endian).
fn encode_samples_32bit(buf : Buffer, samples : Array[Int]) -> Unit {
  let mut i = 0
  while i < samples.length() {
    let s = samples[i]
    buf.write_byte((s & 0xFF).to_byte())
    buf.write_byte(((s >> 8) & 0xFF).to_byte())
    buf.write_byte(((s >> 16) & 0xFF).to_byte())
    buf.write_byte(((s >> 24) & 0xFF).to_byte())
    i = i + 1
  }
}