// A QUIC server connection's Initial-flight processing (RFC 9000 §7, RFC 9001 §5): it
// ties the Initial packet protection, the per-level CRYPTO reassembly, and the TLS 1.3
// handshake runner together. Receiving an Initial packet unprotects it with the keys
// derived from the client's connection id, records the packet number for acknowledgement,
// reassembles the CRYPTO stream, and drives the handshake with the contiguous handshake
// bytes. This is the pure connection core the async UDP transport wraps; feeding it a
// client's Initial packet advances the server handshake to RECVD_CH.

///|
/// A QUIC server connection mid-handshake: the Initial keys, the packet-number/CRYPTO
/// bookkeeping, and the TLS handshake it is driving.
pub struct QuicServerConn {
  initial_keys : QuicPacketKeys
  handshake : TlsServerHandshake
  conn : QuicConnection
}

///|
/// A server connection for a client whose Destination Connection ID is `dcid` (the
/// Initial secret and keys derive from it, RFC 9001 §5.2).
pub fn QuicServerConn::new(dcid : Bytes) -> QuicServerConn {
  {
    initial_keys: quic_packet_keys(quic_client_initial_secret(dcid)),
    handshake: TlsServerHandshake::new(),
    conn: QuicConnection::new(true),
  }
}

///|
/// The current TLS handshake state.
pub fn QuicServerConn::handshake_state(self : QuicServerConn) -> TlsServerState {
  self.handshake.state()
}

///|
/// The transcript hash over the handshake messages processed so far.
pub fn QuicServerConn::transcript_hash(self : QuicServerConn) -> Bytes {
  self.handshake.transcript_hash()
}

///|
/// The raw ClientHello the connection received (empty before one arrives): the source a
/// server runs the ECDHE key_share from to derive its handshake secrets.
pub fn QuicServerConn::client_hello(self : QuicServerConn) -> Bytes {
  self.handshake.client_hello()
}

///|
/// Whether an ACK is owed in the Initial space.
pub fn QuicServerConn::initial_ack_pending(self : QuicServerConn) -> Bool {
  self.conn.space(QuicLevel::Initial).ack_pending()
}

///|
/// Build the server's ServerHello response: encode it, fold it into the transcript, and
/// protect it into an Initial packet addressed to `out_dcid` (the client's source
/// connection id) from `out_scid`, at Initial packet number `pn` (RFC 9001 §5.3). The
/// state stays at RECVD_CH — the server flight is not complete until the Handshake-space
/// messages (EncryptedExtensions, Certificate, CertificateVerify, Finished) are sent by
/// `send_handshake_flight`, which advances it to WAIT_FINISHED.
pub fn QuicServerConn::send_server_hello(
  self : QuicServerConn,
  server_hello : TlsServerHello,
  out_dcid : Bytes,
  out_scid : Bytes,
  pn : Int64,
) -> Bytes {
  let sh_msg = encode_server_hello(server_hello)
  self.handshake.record_sent(sh_msg)
  quic_send_initial(
    1U,
    out_dcid,
    out_scid,
    b"",
    pn,
    4,
    [Crypto(offset=0, data=sh_msg)],
    self.initial_keys,
  )
}

///|
/// Send the server's Handshake-space flight (RFC 8446 §4, RFC 9001 §5): encode
/// EncryptedExtensions, Certificate, and CertificateVerify, fold them into the transcript
/// in order, compute the server Finished as `HMAC(finished_key, transcript hash through
/// CertificateVerify)` over `server_hs_secret`, fold the Finished too, and advance the
/// state past the whole flight (RECVD_CH → WAIT_FINISHED). The four messages form one
/// contiguous CRYPTO stream, protected into a Handshake packet with the handshake-space
/// keys `quic_packet_keys(server_hs_secret)`, addressed to `out_dcid` from `out_scid` at
/// Handshake packet number `pn`. `server_hs_secret` is the server handshake traffic secret
/// the key schedule derives once ECDHE completes.
pub fn QuicServerConn::send_handshake_flight(
  self : QuicServerConn,
  server_hs_secret : Bytes,
  encrypted_extensions : Bytes,
  certificate : Bytes,
  certificate_verify : Bytes,
  out_dcid : Bytes,
  out_scid : Bytes,
  pn : Int64,
) -> Bytes raise {
  let ee = tls_encode_handshake(8, encrypted_extensions)
  let cert = tls_encode_handshake(11, certificate)
  let cv = tls_encode_handshake(15, certificate_verify)
  self.handshake.record_sent(ee)
  self.handshake.record_sent(cert)
  self.handshake.record_sent(cv)
  let verify_data = tls13_finished_verify_data(
    server_hs_secret,
    self.handshake.transcript_hash(),
  )
  let fin = tls_encode_handshake(20, verify_data)
  self.handshake.record_sent(fin)
  self.handshake.sent_flight(false)
  let crypto = bytes_concat(bytes_concat(bytes_concat(ee, cert), cv), fin)
  quic_send_handshake(
    1U,
    out_dcid,
    out_scid,
    pn,
    4,
    [Crypto(offset=0, data=crypto)],
    quic_packet_keys(server_hs_secret),
  )
}

///|
/// Send the server's Handshake-space flight with a real CertificateVerify (RFC 8446 §4.4.3):
/// like `send_handshake_flight`, but instead of taking the CertificateVerify body it signs the
/// transcript through the Certificate with the certificate's ES256 key. Encode
/// EncryptedExtensions and Certificate, fold them, sign the transcript hash then standing (the
/// hash through the Certificate) into the CertificateVerify body, fold it, then the server
/// Finished. A peer holding the certificate's public key can verify the signature and
/// authenticate the server — the real handshake flight, no placeholder CertificateVerify.
pub fn QuicServerConn::send_handshake_flight_signed(
  self : QuicServerConn,
  server_hs_secret : Bytes,
  encrypted_extensions : Bytes,
  certificate : Bytes,
  signing_key : EcdsaPrivateKey,
  out_dcid : Bytes,
  out_scid : Bytes,
  pn : Int64,
) -> Bytes raise {
  let ee = tls_encode_handshake(8, encrypted_extensions)
  let cert = tls_encode_handshake(11, certificate)
  self.handshake.record_sent(ee)
  self.handshake.record_sent(cert)
  let cv_body = tls13_certificate_verify_sign(
    signing_key,
    tls13_cv_context_server,
    self.handshake.transcript_hash(),
  )
  let cv = tls_encode_handshake(15, cv_body)
  self.handshake.record_sent(cv)
  let verify_data = tls13_finished_verify_data(
    server_hs_secret,
    self.handshake.transcript_hash(),
  )
  let fin = tls_encode_handshake(20, verify_data)
  self.handshake.record_sent(fin)
  self.handshake.sent_flight(false)
  let crypto = bytes_concat(bytes_concat(bytes_concat(ee, cert), cv), fin)
  quic_send_handshake(
    1U,
    out_dcid,
    out_scid,
    pn,
    4,
    [Crypto(offset=0, data=crypto)],
    quic_packet_keys(server_hs_secret),
  )
}

///|
/// Receive a client Initial packet: unprotect it, record its number for acknowledgement,
/// reassemble its CRYPTO frames, and drive the handshake with the contiguous handshake
/// bytes. Returns the handshake message types processed. Raises if the packet fails to
/// authenticate.
pub fn QuicServerConn::receive_initial(
  self : QuicServerConn,
  packet : Bytes,
) -> Array[Int] raise {
  let (frames, pn) = match quic_recv_initial(packet, self.initial_keys) {
    Some(v) => v
    None => raise QuicPayloadError("Initial packet failed to authenticate")
  }
  self.conn.on_packet_received(
    QuicLevel::Initial,
    pn,
    quic_payload_is_ack_eliciting(frames),
  )
  let processed : Array[Int] = []
  for frame in frames {
    match frame {
      Crypto(offset~, data~) => {
        let contiguous = self.conn.on_crypto_frame(
          QuicLevel::Initial,
          offset,
          data,
        )
        if contiguous.length() > 0 {
          for msg_type in self.handshake.feed(contiguous) {
            processed.push(msg_type)
          }
        }
      }
      _ => ()
    }
  }
  processed
}

///|
/// Receive the client's Handshake-space flight — in this no-client-authentication path,
/// the client Finished (RFC 8446 §4.4.4): unprotect the Handshake packet with the client
/// handshake keys, reassemble its CRYPTO stream, verify the Finished `verify_data` against
/// `client_hs_secret` over the transcript through the server Finished, then fold it in to
/// advance the handshake to CONNECTED. Returns whether the handshake is now connected with
/// a Finished that authenticated. Raises if the packet fails to authenticate.
pub fn QuicServerConn::receive_handshake(
  self : QuicServerConn,
  packet : Bytes,
  client_hs_keys : QuicPacketKeys,
  client_hs_secret : Bytes,
) -> Bool raise {
  let (frames, pn) = match quic_recv_handshake(packet, client_hs_keys) {
    Some(v) => v
    None => raise QuicPayloadError("Handshake packet failed to authenticate")
  }
  self.conn.on_packet_received(
    QuicLevel::Handshake,
    pn,
    quic_payload_is_ack_eliciting(frames),
  )
  let mut finished_ok = false
  for frame in frames {
    match frame {
      Crypto(offset~, data~) => {
        let contiguous = self.conn.on_crypto_frame(
          QuicLevel::Handshake,
          offset,
          data,
        )
        if contiguous.length() > 0 {
          // The Finished MACs the transcript as it stands now (through the server Finished),
          // so verify against the current hash before folding the client Finished in.
          let th = self.handshake.transcript_hash()
          let view = contiguous[:]
          let mut off = 0
          for ;; {
            match tls_parse_handshake(view[off:]) {
              Some((t, body)) => {
                if t == tls_hs_finished {
                  finished_ok = tls13_finished_verify(
                    client_hs_secret, th, body,
                  )
                }
                off = off + 4 + body.length()
              }
              None => break
            }
          }
          let _ = self.handshake.feed(contiguous)
        }
      }
      _ => ()
    }
  }
  self.handshake.is_connected() && finished_ok
}