///|
/// A positioned, machine-readable failure. Offset is an absolute input byte offset.
pub(all) struct Diagnostic {
  code : String
  offset : Int64
  pid : Int?
} derive(Eq, Debug)

///|
/// Parsed 188-byte TS packet. The owned input and payload cannot alias caller mutation.
pub struct Packet {
  offset : Int64
  pid : Int
  continuity : Int
  payload_start : Bool
  transport_error : Bool
  scrambling : Int
  adaptation_control : Int
  payload : Bytes
  raw : Bytes
} derive(Eq, Debug)

///|
fn fault(code : String, offset : Int64, pid : Int?) -> Diagnostic {
  { code, offset, pid, }
}

///|
/// Parse one complete packet, without guessing alignment or discarding trailing data.
pub fn parse_packet(
  input : Bytes,
  offset? : Int64 = 0L,
) -> Result[Packet, Diagnostic] {
  if offset < 0L || offset > 9223372036854775619L {
    return Err(fault("offset_range", offset, None))
  }
  if input.length() != 188 {
    return Err(fault("packet_size", offset, None))
  }
  if input[0] != 0x47 {
    return Err(fault("sync_byte", offset, None))
  }
  let b1 = input[1].to_int()
  let b3 = input[3].to_int()
  let pid = ((b1 & 0x1f) << 8) | input[2].to_int()
  let control = (b3 >> 4) & 3
  if control == 0 {
    return Err(fault("adaptation_control", offset + 3L, Some(pid)))
  }
  let mut start = 4
  if (control & 2) != 0 {
    let len = input[4].to_int()
    if (control == 2 && len != 183) || (control == 3 && len > 182) {
      return Err(fault("adaptation_length", offset + 4L, Some(pid)))
    }
    start = 5 + len
  }
  Ok({
    offset,
    pid,
    continuity: b3 & 15,
    payload_start: (b1 & 0x40) != 0,
    transport_error: (b1 & 0x80) != 0,
    scrambling: b3 >> 6,
    adaptation_control: control,
    raw: input,
    payload: if (control & 1) != 0 {
      input.view(start~).to_owned()
    } else {
      b""
    },
  })
}