///|
/// The largest integer representable by MoonBit's portable `Int` type.
const MAX_PORTABLE_INT : Int = 2147483647

///|
/// Reads an RFC 3284 big-endian base-128 unsigned integer.
/// Encodings with redundant leading zero groups are rejected.
fn read_varint(cursor : ByteCursor) -> Int raise VcdiffError {
  let start = cursor.offset()
  let mut value = 0
  let mut groups = 0
  let mut first_payload = 0
  while true {
    let byte = cursor.read_byte()
    let payload = byte.to_int() & 0x7f
    if groups == 0 {
      first_payload = payload
    }
    groups += 1
    if groups > 5 || value > (MAX_PORTABLE_INT - payload) / 128 {
      raise IntegerOverflow(offset=start)
    }
    value = value * 128 + payload
    let continues = (byte.to_int() & 0x80) != 0
    if !continues {
      if groups > 1 && first_payload == 0 {
        raise InvalidVarint(
          offset=start,
          reason="non-canonical leading zero group",
        )
      }
      break
    }
  }
  value
}

///|
/// Encodes a non-negative integer using the canonical RFC 3284 representation.
fn encode_varint(value : Int) -> Bytes raise VcdiffError {
  if value < 0 {
    raise InvalidOption(option="varint", reason="must not be negative")
  }
  let groups : Array[Byte] = []
  let mut remaining = value
  groups.push((remaining & 0x7f).to_byte())
  remaining = remaining / 128
  while remaining > 0 {
    groups.push((remaining & 0x7f).to_byte())
    remaining = remaining / 128
  }
  let result : Array[Byte] = []
  for i = groups.length() - 1; i >= 0; i = i - 1 {
    let payload = groups[i].to_int()
    if i == 0 {
      result.push(payload.to_byte())
    } else {
      result.push((payload | 0x80).to_byte())
    }
  }
  Bytes::from_array(result)
}

///|
/// Writes one canonical RFC integer into an existing byte buffer.
fn write_varint(buffer : @buffer.Buffer, value : Int) -> Unit raise VcdiffError {
  buffer.write_bytes(encode_varint(value))
}

///|
/// Returns the encoded byte width without allocating.
fn varint_width(value : Int) -> Int raise VcdiffError {
  if value < 0 {
    raise InvalidOption(option="varint", reason="must not be negative")
  }
  let mut width = 1
  let mut remaining = value / 128
  while remaining > 0 {
    width += 1
    remaining = remaining / 128
  }
  width
}

///|
/// Decodes exactly one canonical RFC 3284 unsigned integer.
///
/// Any bytes following the integer are rejected so callers cannot
/// accidentally ignore malformed suffix data.
pub fn decode_unsigned_integer(data : Bytes) -> Int raise VcdiffError {
  let cursor = ByteCursor::new(data)
  let value = read_varint(cursor)
  let trailing = cursor.remaining()
  if trailing != 0 {
    ignore(cursor.read_exact(trailing))
    raise LengthMismatch(
      offset=cursor.offset() - trailing,
      expected=cursor.offset() - trailing,
      actual=data.length(),
    )
  }
  value
}

///|
/// Encodes one non-negative integer in canonical RFC 3284 form.
pub fn encode_unsigned_integer(value : Int) -> Bytes raise VcdiffError {
  let buffer = @buffer.Buffer(size_hint=varint_width(value))
  write_varint(buffer, value)
  buffer.to_bytes()
}