// moonmp3-encoder — pure MoonBit MP3 encoder.
// Copyright 2026 Sakuraqwq1
// Licensed under the Apache License, Version 2.0.

// Fixed-spectrum streams for the first bitstream vertical slice. This is not
// the PCM encoder: it emits the same 576-coefficient spectrum in every
// granule, which makes it possible to test Huffman coding, side information,
// frame assembly and an independent decoder without the analysis filterbank.

///|
/// Encode a fixed 576-line count1 spectrum into a sequence of MP3 frames.
///
/// Each value must be -1, 0 or 1. Every granule and every channel carries the
/// same spectrum and global gain. `main_data_begin` is always zero and no
/// scalefactors are transmitted, so each granule is self-contained.
pub fn encode_count1_spectrum(
  frames : Int32,
  channels : Int32,
  spectrum : Array[Int32],
  global_gain : Int32,
) -> Bytes raise Count1Error {
  if frames <= 0 {
    raise BadFrames(frames)
  }
  if channels != 1 && channels != 2 {
    raise BadChannels(channels)
  }
  if global_gain < 0 || global_gain > 255 {
    raise BadGain(global_gain)
  }
  if spectrum.length() != 576 {
    raise BadLength(spectrum.length())
  }
  let granule_bits = count1_bits(spectrum)
  let side_bits = if channels == 1 { 136 } else { 256 }
  let required_bits = 32 + side_bits + granule_bits * 2 * channels
  let sizer = FrameSizer::new(Bitrate128kbps, SampleRate44100)
  let out = @buffer.Buffer::Buffer(size_hint=8192)
  for _frame = 0; _frame < frames; _frame = _frame + 1 {
    let size = sizer.next_frame_size()
    if required_bits > size * 8 {
      raise FrameOverflow(required_bits)
    }
    let padding = sizer.padding_of(size)
    let mode = if channels == 1 { ModeMono } else { ModeStereo }
    let w = @bits.BitWriter::new()
    write_header(w, BitrateIndex128, SampleRateIndex44100, mode, padding)
    let scfsi = Array::make(channels, 0)
    let granules = Array::make(
      2 * channels,
      GranuleInfo::count1(granule_bits, global_gain),
    )
    write_side_info(w, channels, 0, scfsi, granules)
    for _gr = 0; _gr < 2; _gr = _gr + 1 {
      for _ch = 0; _ch < channels; _ch = _ch + 1 {
        let _ = write_count1(w, spectrum)
      }
    }
    w.write_bits(0L, size * 8 - w.bit_length())
    let frame = w.finish()
    for index = 0; index < frame.length(); index = index + 1 {
      out.write_byte(frame[index])
    }
  }
  out.to_bytes()
}