// Bytes-based binary utility functions
// These provide efficient binary operations without UTF-16 overhead

// Read 16-bit little-endian integer from bytes

///|
pub fn read_u16_le_bytes(data : Bytes, offset : Int) -> Int {
  if offset + 1 >= data.length() {
    return 0
  }
  let b0 = data[offset].to_int()
  let b1 = data[offset + 1].to_int()
  b0 + (b1 << 8)
}

// Read 32-bit little-endian integer from bytes

///|
pub fn read_u32_le_bytes(data : Bytes, offset : Int) -> Int {
  if offset + 3 >= data.length() {
    return 0
  }
  let b0 = data[offset].to_int()
  let b1 = data[offset + 1].to_int()
  let b2 = data[offset + 2].to_int()
  let b3 = data[offset + 3].to_int()
  b0 + (b1 << 8) + (b2 << 16) + (b3 << 24)
}

// Write 16-bit little-endian integer to bytes

///|
pub fn write_u16_le_bytes(value : Int) -> Bytes {
  let b0 = (value & 0xff).to_byte()
  let b1 = ((value >> 8) & 0xff).to_byte()
  Bytes::from_array([b0, b1])
}

// Write 32-bit little-endian integer to bytes

///|
pub fn write_u32_le_bytes(value : Int) -> Bytes {
  let b0 = (value & 0xff).to_byte()
  let b1 = ((value >> 8) & 0xff).to_byte()
  let b2 = ((value >> 16) & 0xff).to_byte()
  let b3 = ((value >> 24) & 0xff).to_byte()
  Bytes::from_array([b0, b1, b2, b3])
}

// Read 16-bit big-endian integer from bytes

///|
pub fn read_u16_be_bytes(data : Bytes, offset : Int) -> Int {
  if offset + 1 >= data.length() {
    return 0
  }
  let b0 = data[offset].to_int()
  let b1 = data[offset + 1].to_int()
  (b0 << 8) + b1
}

// Read 32-bit big-endian integer from bytes

///|
pub fn read_u32_be_bytes(data : Bytes, offset : Int) -> Int {
  if offset + 3 >= data.length() {
    return 0
  }
  let b0 = data[offset].to_int()
  let b1 = data[offset + 1].to_int()
  let b2 = data[offset + 2].to_int()
  let b3 = data[offset + 3].to_int()
  (b0 << 24) + (b1 << 16) + (b2 << 8) + b3
}

// Write 16-bit big-endian integer to bytes

///|
pub fn write_u16_be_bytes(value : Int) -> Bytes {
  let b0 = ((value >> 8) & 0xff).to_byte()
  let b1 = (value & 0xff).to_byte()
  Bytes::from_array([b0, b1])
}

// Write 32-bit big-endian integer to bytes

///|
pub fn write_u32_be_bytes(value : Int) -> Bytes {
  let b0 = ((value >> 24) & 0xff).to_byte()
  let b1 = ((value >> 16) & 0xff).to_byte()
  let b2 = ((value >> 8) & 0xff).to_byte()
  let b3 = (value & 0xff).to_byte()
  Bytes::from_array([b0, b1, b2, b3])
}

// Concatenate multiple bytes

///|
pub fn concat_bytes(parts : Array[Bytes]) -> Bytes {
  let mut result = Bytes::from_array([])
  for part in parts {
    result = result + part
  }
  result
}

// Create bytes from byte values

///|
pub fn bytes_from_ints(values : Array[Int]) -> Bytes {
  let byte_array = values.map(fn(x) { x.to_byte() })
  Bytes::from_array(byte_array)
}

// Performance comparison functions for demonstration

///|
pub fn compare_string_vs_bytes_write_u32() -> String {
  let test_value = 0x12345678

  // String-based approach (current, inefficient)
  let _string_start = 0 // Placeholder for timing
  let string_result = {
    let b0 = test_value & 0xff
    let b1 = (test_value >> 8) & 0xff
    let b2 = (test_value >> 16) & 0xff
    let b3 = (test_value >> 24) & 0xff
    b0.unsafe_to_char().to_string() +
    b1.unsafe_to_char().to_string() +
    b2.unsafe_to_char().to_string() +
    b3.unsafe_to_char().to_string()
  }
  let _string_end = 0 // Placeholder for timing

  // Bytes-based approach (proposed, efficient)
  let _bytes_start = 0 // Placeholder for timing
  let bytes_result = write_u32_le_bytes(test_value)
  let _bytes_end = 0 // Placeholder for timing
  "String approach: " +
  string_result.length().to_string() +
  " chars, " +
  "Bytes approach: " +
  bytes_result.length().to_string() +
  " bytes\n" +
  "Bytes approach is safer (no unsafe operations) and more efficient"
}