// Audio waveform generators

///|
/// Generate a sine wave.
///
/// # Arguments
/// * `frequency` - Frequency in Hz
/// * `amplitude` - Peak amplitude (e.g., 16000 for 16-bit)
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
///
/// # Returns
/// * `Array[Int]` - Generated samples
pub fn generate_sine(
  frequency : Double,
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []
  let pi = 3.141592653589793

  let mut i = 0
  while i < num_samples {
    let t = Double::from_int(i) / Double::from_int(sample_rate)
    let angle = 2.0 * pi * frequency * t
    let sin_val = angle -
      angle * angle * angle / 6.0 +
      angle * angle * angle * angle * angle / 120.0 -
      angle * angle * angle * angle * angle * angle * angle / 5040.0
    let sample = (amplitude * sin_val).to_int()
    samples.push(sample)
    i = i + 1
  }

  samples
}

///|
/// Generate a square wave.
///
/// # Arguments
/// * `frequency` - Frequency in Hz
/// * `amplitude` - Peak amplitude
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
///
/// # Returns
/// * `Array[Int]` - Generated samples
pub fn generate_square(
  frequency : Double,
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []
  let period = Double::from_int(sample_rate) / frequency

  let mut i = 0
  while i < num_samples {
    let phase = (Double::from_int(i) % period) / period
    let sample = if phase < 0.5 { amplitude } else { -amplitude }
    samples.push(sample.to_int())
    i = i + 1
  }

  samples
}

///|
/// Generate a sawtooth wave.
///
/// # Arguments
/// * `frequency` - Frequency in Hz
/// * `amplitude` - Peak amplitude
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
///
/// # Returns
/// * `Array[Int]` - Generated samples
pub fn generate_sawtooth(
  frequency : Double,
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []
  let period = Double::from_int(sample_rate) / frequency

  let mut i = 0
  while i < num_samples {
    let phase = (Double::from_int(i) % period) / period
    let sample = amplitude * (2.0 * phase - 1.0)
    samples.push(sample.to_int())
    i = i + 1
  }

  samples
}

///|
/// Generate a triangle wave.
///
/// # Arguments
/// * `frequency` - Frequency in Hz
/// * `amplitude` - Peak amplitude
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
///
/// # Returns
/// * `Array[Int]` - Generated samples
pub fn generate_triangle(
  frequency : Double,
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []
  let period = Double::from_int(sample_rate) / frequency

  let mut i = 0
  while i < num_samples {
    let phase = (Double::from_int(i) % period) / period
    let sample = if phase < 0.5 {
      amplitude * (4.0 * phase - 1.0)
    } else {
      amplitude * (3.0 - 4.0 * phase)
    }
    samples.push(sample.to_int())
    i = i + 1
  }

  samples
}

///|
/// Generate white noise.
///
/// # Arguments
/// * `amplitude` - Peak amplitude
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
/// * `seed` - Random seed for reproducibility
///
/// # Returns
/// * `Array[Int]` - Generated samples
pub fn generate_noise(
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
  seed : Int,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []

  // Simple linear congruential generator
  let mut state = seed.abs()

  let mut i = 0
  while i < num_samples {
    // LCG: state = (state * 1103515245 + 12345) & 0x7FFFFFFF
    state = ((state * 1103515245 + 12345) & 0x7FFFFFFF).abs()
    // Map to [-amplitude, amplitude]
    let normalized = (Double::from_int(state) / 1073741824.0 - 1.0) * amplitude
    samples.push(normalized.to_int())
    i = i + 1
  }

  samples
}

///|
/// Generate a chirp (frequency sweep) from start_freq to end_freq.
///
/// # Arguments
/// * `start_freq` - Starting frequency in Hz
/// * `end_freq` - Ending frequency in Hz
/// * `amplitude` - Peak amplitude
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
///
/// # Returns
/// * `Array[Int]` - Generated samples
pub fn generate_chirp(
  start_freq : Double,
  end_freq : Double,
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []
  let pi = 3.141592653589793
  let t_total = duration_sec

  let mut i = 0
  while i < num_samples {
    let t = Double::from_int(i) / Double::from_int(sample_rate)
    // Phase = integral of 2*pi*freq(t) dt where freq(t) = start_freq + (end_freq - start_freq) * t / t_total
    let phase = 2.0 * pi * (start_freq * t + (end_freq - start_freq) * t * t / (2.0 * t_total))
    let sin_val = phase -
      phase * phase * phase / 6.0 +
      phase * phase * phase * phase * phase / 120.0
    let sample = (amplitude * sin_val).to_int()
    samples.push(sample)
    i = i + 1
  }

  samples
}

///|
/// Generate silence (all zeros).
///
/// # Arguments
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
///
/// # Returns
/// * `Array[Int]` - Generated samples (all zeros)
pub fn generate_silence(
  sample_rate : Int,
  duration_sec : Double,
) -> Array[Int] {
  let num_samples = (Double::from_int(sample_rate) * duration_sec).to_int()
  let samples = []

  let mut i = 0
  while i < num_samples {
    samples.push(0)
    i = i + 1
  }

  samples
}

///|
/// Generate a sine wave and return as AudioData ready for encoding.
///
/// # Arguments
/// * `frequency` - Frequency in Hz
/// * `amplitude` - Peak amplitude
/// * `sample_rate` - Sample rate in Hz
/// * `duration_sec` - Duration in seconds
/// * `bits_per_sample` - Bit depth (8, 16, 24, 32)
///
/// # Returns
/// * `AudioData` - Audio data ready for encoding
pub fn generate_sine_wav(
  frequency : Double,
  amplitude : Double,
  sample_rate : Int,
  duration_sec : Double,
  bits_per_sample : Int,
) -> AudioData {
  let samples = generate_sine(frequency, amplitude, sample_rate, duration_sec)
  let bytes_per_sample = bits_per_sample / 8
  let byte_rate = sample_rate * bytes_per_sample
  let info : WavInfo = {
    audio_format: 1,
    num_channels: 1,
    sample_rate,
    byte_rate,
    block_align: bytes_per_sample,
    bits_per_sample,
    data_size: samples.length() * bytes_per_sample,
  }
  { samples, info }
}