// Sending and receiving a whole QUIC Initial packet (RFC 9000 §17.2.2, RFC 9001 §5): the
// send side assembles the frames into a payload and protects it; the receive side finds
// the packet-number field, removes protection, and parses the payload back into frames.
// This ties the payload assembly, the Initial packet protection, and the frame codec
// into the packet a QUIC endpoint actually puts on and takes off the wire.

///|
/// The offset of the packet-number field in a received Initial packet, walking its long
/// header: first byte, version, the two connection ids, the token, and the length field
/// (RFC 9000 §17.2.2).
pub fn quic_initial_pn_offset(packet : Bytes) -> Int raise QuicPayloadError {
  let view = packet[:]
  let mut off = 1 + 4 // first byte + version
  if off + 1 > view.length() {
    raise QuicPayloadError("Initial packet truncated before DCID")
  }
  let dcid_len = view[off].to_int()
  off = off + 1 + dcid_len
  if off + 1 > view.length() {
    raise QuicPayloadError("Initial packet truncated before SCID")
  }
  let scid_len = view[off].to_int()
  off = off + 1 + scid_len
  let (token_len, tl) = match quic_varint_decode(view[off:]) {
    Some(v) => v
    None => raise QuicPayloadError("Initial packet truncated in token length")
  }
  off = off + tl + token_len.to_int()
  let (_length, ll) = match quic_varint_decode(view[off:]) {
    Some(v) => v
    None => raise QuicPayloadError("Initial packet truncated in length field")
  }
  off + ll
}

///|
/// Build a protected Initial packet carrying `frames`: encode them into a payload and
/// protect it with `keys` (RFC 9001 §5.3, §5.4).
pub fn quic_send_initial(
  version : UInt,
  dcid : Bytes,
  scid : Bytes,
  token : Bytes,
  packet_number : Int64,
  pn_length : Int,
  frames : Array[QuicFrame],
  keys : QuicPacketKeys,
) -> Bytes {
  quic_protect_initial(
    version,
    dcid,
    scid,
    token,
    packet_number,
    pn_length,
    quic_encode_payload(frames),
    keys.key,
    keys.iv,
    keys.hp,
  )
}

///|
/// Receive a protected Initial `packet` with `keys`: remove protection, parse the
/// payload, and return its frames and packet number. `None` if authentication fails.
pub fn quic_recv_initial(
  packet : Bytes,
  keys : QuicPacketKeys,
) -> (Array[QuicFrame], Int64)? raise QuicPayloadError {
  let pn_offset = quic_initial_pn_offset(packet)
  match quic_unprotect_initial(packet, pn_offset, keys.key, keys.iv, keys.hp) {
    Some((payload, pn)) => Some((quic_parse_payload(payload), pn))
    None => None
  }
}