// MoonDNS - Pure MoonBit Authoritative DNS Server
// Copyright 2026 chgttyyr
// Licensed under the Apache-2.0 License.

///|
/// ByteWriter provides dynamic, expandable big-endian binary stream writing.
pub(all) struct ByteWriter {
  buf : Array[Byte]
} derive(Debug)

///|
/// Create an empty ByteWriter
pub fn ByteWriter::new() -> ByteWriter {
  { buf: [], }
}

///|
/// Current length of accumulated bytes
pub fn ByteWriter::length(self : ByteWriter) -> Int {
  self.buf.length()
}

///|
/// Clear the internal buffer
pub fn ByteWriter::clear(self : ByteWriter) -> Unit {
  self.buf.clear()
}

///|
/// Write a single byte
pub fn ByteWriter::write_byte(self : ByteWriter, b : Byte) -> Unit {
  self.buf.push(b)
}

///|
/// Write a big-endian 16-bit unsigned integer
pub fn ByteWriter::write_uint16(self : ByteWriter, val : UInt16) -> Unit {
  let v = val.to_int()
  let b0 = ((v >> 8) & 0xff).to_byte()
  let b1 = (v & 0xff).to_byte()
  self.buf.push(b0)
  self.buf.push(b1)
}

///|
/// Write a big-endian 32-bit unsigned integer
pub fn ByteWriter::write_uint32(self : ByteWriter, val : UInt) -> Unit {
  let b0 = ((val >> 24) & 0xff).to_byte()
  let b1 = ((val >> 16) & 0xff).to_byte()
  let b2 = ((val >> 8) & 0xff).to_byte()
  let b3 = (val & 0xff).to_byte()
  self.buf.push(b0)
  self.buf.push(b1)
  self.buf.push(b2)
  self.buf.push(b3)
}

///|
/// Write an entire Bytes sequence
pub fn ByteWriter::write_bytes(self : ByteWriter, bytes : Bytes) -> Unit {
  for i = 0; i < bytes.length(); i = i + 1 {
    self.buf.push(bytes[i])
  }
}

///|
/// Write a FixedArray of bytes
pub fn ByteWriter::write_fixed_bytes(
  self : ByteWriter,
  bytes : FixedArray[Byte],
) -> Unit {
  for i = 0; i < bytes.length(); i = i + 1 {
    self.buf.push(bytes[i])
  }
}

///|
/// Overwrite a 16-bit unsigned integer at a previously written position (patching)
pub fn ByteWriter::patch_uint16(
  self : ByteWriter,
  pos : Int,
  val : UInt16,
) -> Result[Unit, @types.DnsError] {
  if pos < 0 || pos + 2 > self.buf.length() {
    return Err(
      @types.BufferOverflow("Patch position out of range: " + pos.to_string()),
    )
  }
  let v = val.to_int()
  self.buf[pos] = ((v >> 8) & 0xff).to_byte()
  self.buf[pos + 1] = (v & 0xff).to_byte()
  Ok(())
}

///|
/// Convert internal buffer to immutable Bytes
pub fn ByteWriter::to_bytes(self : ByteWriter) -> Bytes {
  Bytes::from_array(self.buf)
}