///| Bit reader for deflate streams (LSB-first)

///|
priv struct BitReader {
  data : Bytes
  mut byte_pos : Int
  mut bit_buf : UInt64
  mut bit_count : Int
}

///|
fn BitReader::new(data : Bytes, start : Int) -> BitReader {
  { data, byte_pos: start, bit_buf: 0, bit_count: 0 }
}

///|
fn BitReader::ensure_bits(self : BitReader, n : Int) -> Unit raise ZlibError {
  while self.bit_count < n {
    let remaining = self.data.length() - self.byte_pos
    if remaining <= 0 {
      raise ZlibError::InvalidData("Unexpected end of deflate stream")
    }
    // Batch 4 bytes when possible to reduce loop overhead in hot paths.
    // Use UInt64 to keep shifts safe for native targets.
    if remaining >= 4 && self.bit_count <= 32 {
      let b0 = self.data[self.byte_pos].to_uint64()
      let b1 = self.data[self.byte_pos + 1].to_uint64()
      let b2 = self.data[self.byte_pos + 2].to_uint64()
      let b3 = self.data[self.byte_pos + 3].to_uint64()
      self.byte_pos = self.byte_pos + 4
      self.bit_buf = self.bit_buf |
        (b0 << self.bit_count) |
        (b1 << (self.bit_count + 8)) |
        (b2 << (self.bit_count + 16)) |
        (b3 << (self.bit_count + 24))
      self.bit_count = self.bit_count + 32
    } else if remaining >= 2 && self.bit_count <= 48 {
      let b0 = self.data[self.byte_pos].to_uint64()
      let b1 = self.data[self.byte_pos + 1].to_uint64()
      self.byte_pos = self.byte_pos + 2
      self.bit_buf = self.bit_buf |
        (b0 << self.bit_count) |
        (b1 << (self.bit_count + 8))
      self.bit_count = self.bit_count + 16
    } else {
      let b = self.data[self.byte_pos].to_uint64()
      self.byte_pos = self.byte_pos + 1
      self.bit_buf = self.bit_buf | (b << self.bit_count)
      self.bit_count = self.bit_count + 8
    }
  }
}

///|
fn BitReader::peek_bits(self : BitReader, n : Int) -> Int raise ZlibError {
  if n == 0 {
    return 0
  }
  self.ensure_bits(n)
  let one : UInt64 = 1
  let mask : UInt64 = (one << n) - 1
  (self.bit_buf & mask).to_int()
}

///|
fn BitReader::drop_bits(self : BitReader, n : Int) -> Unit {
  if n == 0 {
    return
  }
  self.bit_buf = self.bit_buf >> n
  self.bit_count = self.bit_count - n
}

///|
fn BitReader::read_bits(self : BitReader, n : Int) -> Int raise ZlibError {
  let result = self.peek_bits(n)
  self.drop_bits(n)
  result
}

///|
fn BitReader::align_byte(self : BitReader) -> Unit {
  let full_bytes = self.bit_count / 8
  if full_bytes > 0 {
    self.byte_pos = self.byte_pos - full_bytes
  }
  self.bit_buf = 0
  self.bit_count = 0
}

///|

///|
fn BitReader::read_u16_le_aligned(self : BitReader) -> Int raise ZlibError {
  if self.bit_count != 0 {
    self.align_byte()
  }
  if self.byte_pos + 2 > self.data.length() {
    raise ZlibError::InvalidData("Unexpected end of deflate stream")
  }
  let b0 = self.data[self.byte_pos].to_int()
  let b1 = self.data[self.byte_pos + 1].to_int()
  self.byte_pos = self.byte_pos + 2
  b0 | (b1 << 8)
}

///|
fn BitReader::read_bytes_aligned(
  self : BitReader,
  output : Array[Byte],
  len : Int,
) -> Unit raise ZlibError {
  if self.bit_count != 0 {
    self.align_byte()
  }
  if self.byte_pos + len > self.data.length() {
    raise ZlibError::InvalidData("Unexpected end of deflate stream")
  }
  for i in 0.. Int {
  self.byte_pos
}