// LSB-first bit sink for the encode pipeline. DEFLATE packs bits LSB-first
// into bytes, but Huffman codes are written MSB-first.

///|
priv struct BitWriter {
  out : Array[Byte]
  mut bitbuf : Int
  mut bit_count : Int // bits currently held in `bitbuf`, not yet flushed to a byte
  direct_output : FixedArray[Byte]?
  mut direct_pos : Int
  mut overflowed : Bool
}

///|
fn BitWriter::BitWriter() -> BitWriter {
  {
    out: [],
    bitbuf: 0,
    bit_count: 0,
    direct_output: None,
    direct_pos: 0,
    overflowed: false,
  }
}

///|
/// Create a bit writer that emits directly into `output`. Writes past its end
/// are recorded so the caller can report capacity exhaustion after encoding.
fn BitWriter::into(output : FixedArray[Byte]) -> BitWriter {
  {
    out: [],
    bitbuf: 0,
    bit_count: 0,
    direct_output: Some(output),
    direct_pos: 0,
    overflowed: false,
  }
}

///|
/// Emit one whole byte to the configured destination. The normal writer grows
/// `out`; a direct writer keeps counting after capacity exhaustion so all block
/// planning code can remain allocation-free and branch-free at call sites.
#inline
fn BitWriter::write_byte(self : BitWriter, byte : Byte) -> Unit {
  if self.direct_output is Some(output) {
    if self.direct_pos < output.length() {
      output[self.direct_pos] = byte
    } else {
      self.overflowed = true
    }
    self.direct_pos = self.direct_pos + 1
  } else {
    self.out.push(byte)
  }
}

///|
/// Write a byte-aligned payload. Preserve the direct writer's overflow count
/// even if a previous header or payload already exhausted the output buffer.
fn BitWriter::write_bytes(
  self : BitWriter,
  input : Bytes,
  offset : Int,
  length : Int,
) -> Unit {
  if self.direct_output is Some(output) {
    let count = length.min((output.length() - self.direct_pos).max(0))
    if count > 0 {
      output.blit_from_bytes(self.direct_pos, input, offset, count)
    }
    self.direct_pos = self.direct_pos + length
    if count < length {
      self.overflowed = true
    }
  } else {
    for i in offset..<(offset + length) {
      self.out.push(input[i])
    }
  }
}

///|
fn BitWriter::write_bit(self : BitWriter, bit : Int) -> Unit {
  self.bitbuf = self.bitbuf | (bit << self.bit_count)
  self.bit_count = self.bit_count + 1
  if self.bit_count == 8 {
    self.write_byte((self.bitbuf & 0xFF).to_byte())
    self.bitbuf = 0
    self.bit_count = 0
  }
}

///|
/// Write the low `n` bits of `value`, LSB-first. Batched: the bits are shifted
/// into the accumulator in one step and complete bytes flushed whole, instead
/// of looping one bit at a time.
fn BitWriter::write_bits(self : BitWriter, value : Int, n : Int) -> Unit {
  self.bitbuf = self.bitbuf | ((value & ((1 << n) - 1)) << self.bit_count)
  self.bit_count = self.bit_count + n
  while self.bit_count >= 8 {
    self.write_byte((self.bitbuf & 0xFF).to_byte())
    self.bitbuf = self.bitbuf >> 8
    self.bit_count = self.bit_count - 8
  }
}

///|
/// Write an already-bit-reversed Huffman code, LSB-first.
fn BitWriter::write_rcode(self : BitWriter, code : UInt, n : Int) -> Unit {
  self.write_bits(code.reinterpret_as_int(), n)
}

///|
/// Pad any sub-byte remainder in `bitbuf` out to a whole byte (zero-filling the
/// high bits) and emit it. Required before a byte-aligned stored block and at
/// the very end of a stream
fn BitWriter::flush(self : BitWriter) -> Unit {
  if self.bit_count > 0 {
    self.write_byte((self.bitbuf & 0xFF).to_byte())
    self.bitbuf = 0
    self.bit_count = 0
  }
}