// Copyright 2026 Noverberrain.
// SPDX-License-Identifier: Apache-2.0

///|
priv struct KeyPrefix {
  start : Int32
  type_offset : Int32
  object_type : Byte
  expires_at_ms : Int64?
  idle_seconds : UInt64?
  frequency : Byte?
}

///|
fn is_object_type(value : Byte) -> Bool {
  let value = value.to_int()
  (value >= 0 && value <= 7) || (value >= 9 && value <= 21)
}

///|
// Called after the first metadata opcode. No clock or expiry filtering is used.
// Unknown encodings are never skipped. Subsequent record parsing arrives in F3.
fn Reader::read_key_prefix(
  self : Reader,
  first : Byte,
  start : Int32,
) -> KeyPrefix raise ParseError {
  let entry_pos = self.pos
  errdefer {
    self.pos = entry_pos
  }
  let mut expires_at_ms : Int64? = None
  let mut idle_seconds : UInt64? = None
  let mut frequency : Byte? = None
  for opcode = first, offset = start {
    match opcode.to_int() {
      252 | 253 => {
        if expires_at_ms is Some(_) {
          raise DuplicateKeyMetadata(offset~, opcode~)
        }
        expires_at_ms = Some(
          if opcode == b'\xfc' {
            self.read_i64_le()
          } else {
            self.read_i32_le().to_int64() * 1000L
          },
        )
      }
      248 => {
        if idle_seconds is Some(_) {
          raise DuplicateKeyMetadata(offset~, opcode~)
        }
        idle_seconds = Some(self.read_count())
      }
      249 => {
        if frequency is Some(_) {
          raise DuplicateKeyMetadata(offset~, opcode~)
        }
        frequency = Some(self.read_u8())
      }
      _ => {
        if is_object_type(opcode) {
          return {
            start,
            type_offset: offset,
            object_type: opcode,
            expires_at_ms,
            idle_seconds,
            frequency,
          }
        }
        if opcode.to_int() >= 245 {
          raise DanglingKeyMetadata(offset=start)
        }
        raise UnsupportedOpcode(offset~, opcode~)
      }
    }
    let next_offset = self.pos
    let next_opcode = self.read_u8()
    continue next_opcode, next_offset
  }
}