///|
/// VLR payloads are opaque. GeoTIFF/WKT records are retained without reprojection.
pub(all) struct Vlr {
  user_id : String
  record_id : Int32
  description : String
  payload : Bytes
} derive(Debug, Eq)

///|
pub fn Vlr::validate(self : Vlr) -> Unit raise LasError {
  require(
    self.record_id >= 0 && self.record_id <= 65535,
    "invalid VLR record ID",
  )
  require(self.payload.length() <= 65535, "VLR payload exceeds uint16 length")
  let probe : Array[Byte] = []
  put_text(probe, self.user_id, 16)
  put_text(probe, self.description, 32)
}

///|
pub fn read_vlrs(
  data : Bytes,
  header : Header,
  limits~ : Limits = Limits::default(),
) -> (Array[Vlr], Bytes) raise LasError {
  limits.validate()
  if data.length() > limits.max_bytes {
    raise Limit("input byte budget exceeded")
  }
  if header.vlr_count < 0 || header.vlr_count > limits.max_vlrs {
    raise Limit("VLR budget exceeded")
  }
  require(
    header.minor == 2 || header.minor == 4,
    "unsupported metadata header version",
  )
  let start = if header.minor == 2 { 227 } else { 375 }
  let r = Reader::new(data, start, header.point_offset)
  checked_size(header.vlr_count, 54, header.point_offset - start)
  let records : Array[Vlr] = []
  for _ in 0.. Bytes raise LasError {
  let out : Array[Byte] = []
  for record in records {
    record.validate()
    put16(out, 0)
    put_text(out, record.user_id, 16)
    put16(out, record.record_id)
    put16(out, record.payload.length())
    put_text(out, record.description, 32)
    append(out, record.payload)
  }
  bytes_of(out)
}

///|
pub fn vlrs_named(
  records : Array[Vlr],
  user_id : String,
  record_id : Int32,
) -> Array[Vlr] {
  records.filter(r => r.user_id == user_id && r.record_id == record_id)
}

///|
pub extend Vlr with @debug.Debug::{to_repr}

///|
pub extend Vlr with Eq::{equal, not_equal}

///|
fn metadata_end(
  records : Array[Vlr],
  gap : Bytes,
  minor : Int32,
  limits : Limits,
) -> Int32 raise LasError {
  let mut size = if minor == 2 { 227 } else { 375 }
  for v in records {
    v.validate()
    let n = 54 + v.payload.length()
    if n > limits.max_bytes - size {
      raise Limit("metadata byte budget exceeded")
    }
    size += n
  }
  if gap.length() > limits.max_bytes - size {
    raise Limit("gap byte budget exceeded")
  }
  size + gap.length()
}