/// UUID Version 8 (Custom) implementation

///|
/// Generate a custom UUID (version 8)
/// The caller is responsible for providing the custom data
pub fn v8(custom_data : FixedArray[Byte]) -> Uuid {
  if custom_data.length() != 16 {
    abort("Custom data must be exactly 16 bytes")
  }
  let bytes : FixedArray[Byte] = FixedArray::make(16, b'\x00')

  // Copy custom data
  for i = 0; i < 16; i = i + 1 {
    bytes[i] = custom_data[i]
  }

  // Set version and variant bits
  set_variant_and_version(bytes, Version::V8)
  Uuid::new(bytes)
}

///|
/// Generate a custom UUID from a 128-bit integer
pub fn v8_from_int128(high : Int64, low : Int64) -> Uuid {
  let bytes : FixedArray[Byte] = FixedArray::make(16, b'\x00')

  // Convert high 64 bits to bytes
  for i = 0; i < 8; i = i + 1 {
    bytes[i] = (high >> ((7 - i) * 8)).land(0xFFL).to_int().to_byte()
  }

  // Convert low 64 bits to bytes
  for i = 0; i < 8; i = i + 1 {
    bytes[8 + i] = (low >> ((7 - i) * 8)).land(0xFFL).to_int().to_byte()
  }

  // Set version and variant bits
  set_variant_and_version(bytes, Version::V8)
  Uuid::new(bytes)
}

///|
/// Generate a custom UUID with application-specific structure
/// Example: counter-based UUID with specific formatting
pub fn v8_counter(counter : Int64, node_id : Int, application_id : Int) -> Uuid {
  let bytes : FixedArray[Byte] = FixedArray::make(16, b'\x00')

  // First 8 bytes: counter
  for i = 0; i < 8; i = i + 1 {
    bytes[i] = (counter >> ((7 - i) * 8)).land(0xFFL).to_int().to_byte()
  }

  // Next 4 bytes: node_id
  for i = 0; i < 4; i = i + 1 {
    bytes[8 + i] = (node_id >> ((3 - i) * 8)).land(0xFF).to_byte()
  }

  // Last 4 bytes: application_id  
  for i = 0; i < 4; i = i + 1 {
    bytes[12 + i] = (application_id >> ((3 - i) * 8)).land(0xFF).to_byte()
  }

  // Set version and variant bits
  set_variant_and_version(bytes, Version::V8)
  Uuid::new(bytes)
}

///|
/// Generate a custom UUID with mixed content (timestamp + random + custom)
pub fn v8_mixed(timestamp_ms : Int64, custom_suffix : Int) -> Uuid {
  let bytes : FixedArray[Byte] = FixedArray::make(16, b'\x00')

  // First 6 bytes: timestamp (like v7)
  bytes[0] = (timestamp_ms >> 40).land(0xFFL).to_int().to_byte()
  bytes[1] = (timestamp_ms >> 32).land(0xFFL).to_int().to_byte()
  bytes[2] = (timestamp_ms >> 24).land(0xFFL).to_int().to_byte()
  bytes[3] = (timestamp_ms >> 16).land(0xFFL).to_int().to_byte()
  bytes[4] = (timestamp_ms >> 8).land(0xFFL).to_int().to_byte()
  bytes[5] = timestamp_ms.land(0xFFL).to_int().to_byte()

  // Next 4 bytes: random
  let random_bytes = random_bytes(4)
  for i = 0; i < 4; i = i + 1 {
    bytes[6 + i] = random_bytes[i]
  }

  // Last 6 bytes: custom suffix
  for i = 0; i < 6; i = i + 1 {
    bytes[10 + i] = (custom_suffix >> ((5 - i) * 8)).land(0xFF).to_byte()
  }

  // Set version and variant bits
  set_variant_and_version(bytes, Version::V8)
  Uuid::new(bytes)
}

///|
/// Extract custom data from a version 8 UUID (excluding version/variant bits)
pub fn extract_custom_data(uuid : Uuid) -> FixedArray[Byte]? {
  match uuid.version() {
    Some(Version::V8) => {
      let bytes = uuid.bytes()
      let custom_data : FixedArray[Byte] = FixedArray::make(16, b'\x00')

      // Copy all bytes (caller can handle version/variant bits if needed)
      for i = 0; i < 16; i = i + 1 {
        custom_data[i] = bytes[i]
      }
      Some(custom_data)
    }
    _ => None
  }
}