package quic

import (
	crand 
	
	
	
	

	
	
	
	
	
	
)

var errNothingToPack = errors.New("nothing to pack")

type packer interface {
	PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, now monotime.Time, v protocol.Version) (*coalescedPacket, error)
	PackAckOnlyPacket(maxPacketSize protocol.ByteCount, now monotime.Time, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
	AppendPacket(_ *packetBuffer, maxPacketSize protocol.ByteCount, now monotime.Time, v protocol.Version) (shortHeaderPacket, error)
	PackPTOProbePacket(_ protocol.EncryptionLevel, _ protocol.ByteCount, addPingIfEmpty bool, now monotime.Time, v protocol.Version) (*coalescedPacket, error)
	PackConnectionClose(*qerr.TransportError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
	PackApplicationClose(*qerr.ApplicationError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
	PackPathProbePacket(protocol.ConnectionID, []ackhandler.Frame, protocol.Version) (shortHeaderPacket, *packetBuffer, error)
	PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)

	SetToken([]byte)
}

type sealer interface {
	handshake.LongHeaderSealer
}

type payload struct {
	streamFrames []ackhandler.StreamFrame
	frames       []ackhandler.Frame
	ack          *wire.AckFrame
	length       protocol.ByteCount
}

type longHeaderPacket struct {
	header       *wire.ExtendedHeader
	ack          *wire.AckFrame
	frames       []ackhandler.Frame
	streamFrames []ackhandler.StreamFrame // only used for 0-RTT packets

	length protocol.ByteCount
}

type shortHeaderPacket struct {
	PacketNumber         protocol.PacketNumber
	Frames               []ackhandler.Frame
	StreamFrames         []ackhandler.StreamFrame
	Ack                  *wire.AckFrame
	Length               protocol.ByteCount
	IsPathMTUProbePacket bool
	IsPathProbePacket    bool

	// used for logging
	DestConnID      protocol.ConnectionID
	PacketNumberLen protocol.PacketNumberLen
	KeyPhase        protocol.KeyPhaseBit
}

func ( *shortHeaderPacket) () bool { return ackhandler.HasAckElicitingFrames(.Frames) }

type coalescedPacket struct {
	buffer         *packetBuffer
	longHdrPackets []*longHeaderPacket
	shortHdrPacket *shortHeaderPacket
}

// IsOnlyShortHeaderPacket says if this packet only contains a short header packet (and no long header packets).
func ( *coalescedPacket) () bool {
	return len(.longHdrPackets) == 0 && .shortHdrPacket != nil
}

func ( *longHeaderPacket) () protocol.EncryptionLevel {
	//nolint:exhaustive // Will never be called for Retry packets (and they don't have encrypted data).
	switch .header.Type {
	case protocol.PacketTypeInitial:
		return protocol.EncryptionInitial
	case protocol.PacketTypeHandshake:
		return protocol.EncryptionHandshake
	case protocol.PacketType0RTT:
		return protocol.Encryption0RTT
	default:
		panic("can't determine encryption level")
	}
}

func ( *longHeaderPacket) () bool { return ackhandler.HasAckElicitingFrames(.frames) }

type packetNumberManager interface {
	PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
	PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
}

type sealingManager interface {
	GetInitialSealer() (handshake.LongHeaderSealer, error)
	GetHandshakeSealer() (handshake.LongHeaderSealer, error)
	Get0RTTSealer() (handshake.LongHeaderSealer, error)
	Get1RTTSealer() (handshake.ShortHeaderSealer, error)
}

type frameSource interface {
	HasData() bool
	Append([]ackhandler.Frame, []ackhandler.StreamFrame, protocol.ByteCount, monotime.Time, protocol.Version) ([]ackhandler.Frame, []ackhandler.StreamFrame, protocol.ByteCount)
}

type ackFrameSource interface {
	GetAckFrame(_ protocol.EncryptionLevel, now monotime.Time, onlyIfQueued bool) *wire.AckFrame
}

type packetPacker struct {
	srcConnID     protocol.ConnectionID
	getDestConnID func() protocol.ConnectionID

	perspective protocol.Perspective
	cryptoSetup sealingManager

	initialStream   *initialCryptoStream
	handshakeStream *cryptoStream

	token []byte

	pnManager           packetNumberManager
	framer              frameSource
	acks                ackFrameSource
	datagramQueue       *datagramQueue
	retransmissionQueue *retransmissionQueue
	rand                rand.Rand

	numNonAckElicitingAcks int
}

var _ packer = &packetPacker{}

func newPacketPacker(
	 protocol.ConnectionID,
	 func() protocol.ConnectionID,
	 *initialCryptoStream,
	 *cryptoStream,
	 packetNumberManager,
	 *retransmissionQueue,
	 sealingManager,
	 frameSource,
	 ackFrameSource,
	 *datagramQueue,
	 protocol.Perspective,
) *packetPacker {
	var  [16]byte
	_, _ = crand.Read([:])

	return &packetPacker{
		cryptoSetup:         ,
		getDestConnID:       ,
		srcConnID:           ,
		initialStream:       ,
		handshakeStream:     ,
		retransmissionQueue: ,
		datagramQueue:       ,
		perspective:         ,
		framer:              ,
		acks:                ,
		rand:                *rand.New(rand.NewPCG(binary.BigEndian.Uint64([:8]), binary.BigEndian.Uint64([8:]))),
		pnManager:           ,
	}
}

// PackConnectionClose packs a packet that closes the connection with a transport error.
func ( *packetPacker) ( *qerr.TransportError,  protocol.ByteCount,  protocol.Version) (*coalescedPacket, error) {
	var  string
	// don't send details of crypto errors
	if !.ErrorCode.IsCryptoError() {
		 = .ErrorMessage
	}
	return .packConnectionClose(false, uint64(.ErrorCode), .FrameType, , , )
}

// PackApplicationClose packs a packet that closes the connection with an application error.
func ( *packetPacker) ( *qerr.ApplicationError,  protocol.ByteCount,  protocol.Version) (*coalescedPacket, error) {
	return .packConnectionClose(true, uint64(.ErrorCode), 0, .ErrorMessage, , )
}

func ( *packetPacker) (
	 bool,
	 uint64,
	 uint64,
	 string,
	 protocol.ByteCount,
	 protocol.Version,
) (*coalescedPacket, error) {
	var  [4]sealer
	var  [3]*wire.ExtendedHeader
	var  [4]payload
	var  protocol.ByteCount
	var  protocol.ConnectionID
	var  protocol.PacketNumber
	var  protocol.PacketNumberLen
	var  protocol.KeyPhaseBit // only set for 1-RTT
	var  uint8
	 := [4]protocol.EncryptionLevel{protocol.EncryptionInitial, protocol.EncryptionHandshake, protocol.Encryption0RTT, protocol.Encryption1RTT}
	for ,  := range  {
		if .perspective == protocol.PerspectiveServer &&  == protocol.Encryption0RTT {
			continue
		}
		 := &wire.ConnectionCloseFrame{
			IsApplicationError: ,
			ErrorCode:          ,
			FrameType:          ,
			ReasonPhrase:       ,
		}
		// don't send application errors in Initial or Handshake packets
		if  && ( == protocol.EncryptionInitial ||  == protocol.EncryptionHandshake) {
			.IsApplicationError = false
			.ErrorCode = uint64(qerr.ApplicationErrorErrorCode)
			.ReasonPhrase = ""
		}
		 := payload{
			frames: []ackhandler.Frame{{Frame: }},
			length: .Length(),
		}

		var  sealer
		var  error
		switch  {
		case protocol.EncryptionInitial:
			,  = .cryptoSetup.GetInitialSealer()
		case protocol.EncryptionHandshake:
			,  = .cryptoSetup.GetHandshakeSealer()
		case protocol.Encryption0RTT:
			,  = .cryptoSetup.Get0RTTSealer()
		case protocol.Encryption1RTT:
			var  handshake.ShortHeaderSealer
			,  = .cryptoSetup.Get1RTTSealer()
			if  == nil {
				 = .KeyPhase()
			}
			 = 
		}
		if  == handshake.ErrKeysNotYetAvailable ||  == handshake.ErrKeysDropped {
			continue
		}
		if  != nil {
			return nil, 
		}
		[] = 
		var  *wire.ExtendedHeader
		if  == protocol.Encryption1RTT {
			 = .getDestConnID()
			,  = .pnManager.PeekPacketNumber(protocol.Encryption1RTT)
			 += .shortHeaderPacketLength(, , )
		} else {
			 = .getLongHeader(, )
			[] = 
			 += .longHeaderPacketLength(, , ) + protocol.ByteCount(.Overhead())
			++
		}
		[] = 
	}
	 := getPacketBuffer()
	 := &coalescedPacket{
		buffer:         ,
		longHdrPackets: make([]*longHeaderPacket, 0, ),
	}
	for ,  := range  {
		if [] == nil {
			continue
		}
		if  == protocol.Encryption1RTT {
			,  := .appendShortHeaderPacket(, , , , , [], 0, , [], false, )
			if  != nil {
				return nil, 
			}
			.shortHdrPacket = &
		} else {
			var  protocol.ByteCount
			if  == protocol.EncryptionInitial {
				 = .initialPaddingLen([].frames, , )
			}
			,  := .appendLongHeaderPacket(, [], [], , , [], )
			if  != nil {
				return nil, 
			}
			.longHdrPackets = append(.longHdrPackets, )
		}
	}
	return , nil
}

// longHeaderPacketLength calculates the length of a serialized long header packet.
// It takes into account that packets that have a tiny payload need to be padded,
// such that len(payload) + packet number len >= 4 + AEAD overhead
func ( *packetPacker) ( *wire.ExtendedHeader,  payload,  protocol.Version) protocol.ByteCount {
	var  protocol.ByteCount
	 := protocol.ByteCount(.PacketNumberLen)
	if .length < 4- {
		 = 4 -  - .length
	}
	return .GetLength() + .length + 
}

// shortHeaderPacketLength calculates the length of a serialized short header packet.
// It takes into account that packets that have a tiny payload need to be padded,
// such that len(payload) + packet number len >= 4 + AEAD overhead
func ( *packetPacker) ( protocol.ConnectionID,  protocol.PacketNumberLen,  payload) protocol.ByteCount {
	var  protocol.ByteCount
	if .length < 4-protocol.ByteCount() {
		 = 4 - protocol.ByteCount() - .length
	}
	return wire.ShortHeaderLen(, ) + .length + 
}

// size is the expected size of the packet, if no padding was applied.
func ( *packetPacker) ( []ackhandler.Frame, ,  protocol.ByteCount) protocol.ByteCount {
	// For the server, only ack-eliciting Initial packets need to be padded.
	if .perspective == protocol.PerspectiveServer && !ackhandler.HasAckElicitingFrames() {
		return 0
	}
	if  >=  {
		return 0
	}
	return  - 
}

// PackCoalescedPacket packs a new packet.
// It packs an Initial / Handshake if there is data to send in these packet number spaces.
// It should only be called before the handshake is confirmed.
func ( *packetPacker) ( bool,  protocol.ByteCount,  monotime.Time,  protocol.Version) (*coalescedPacket, error) {
	var (
		, ,                             *wire.ExtendedHeader
		, , ,  payload
		                                              protocol.PacketNumber
		                                           protocol.PacketNumberLen
	)
	// Try packing an Initial packet.
	,  := .cryptoSetup.GetInitialSealer()
	if  != nil &&  != handshake.ErrKeysDropped {
		return nil, 
	}
	var  protocol.ByteCount
	if  != nil {
		,  = .maybeGetCryptoPacket(
			-protocol.ByteCount(.Overhead()),
			protocol.EncryptionInitial,
			,
			false,
			,
			,
		)
		if .length > 0 {
			 += .longHeaderPacketLength(, , ) + protocol.ByteCount(.Overhead())
		}
	}

	// Add a Handshake packet.
	var  sealer
	if ( &&  == 0) || (! &&  < -protocol.MinCoalescedPacketSize) {
		var  error
		,  = .cryptoSetup.GetHandshakeSealer()
		if  != nil &&  != handshake.ErrKeysDropped &&  != handshake.ErrKeysNotYetAvailable {
			return nil, 
		}
		if  != nil {
			,  = .maybeGetCryptoPacket(
				--protocol.ByteCount(.Overhead()),
				protocol.EncryptionHandshake,
				,
				false,
				,
				,
			)
			if .length > 0 {
				 := .longHeaderPacketLength(, , ) + protocol.ByteCount(.Overhead())
				 += 
			}
		}
	}

	// Add a 0-RTT / 1-RTT packet.
	var  sealer
	var  handshake.ShortHeaderSealer
	var  protocol.ConnectionID
	var  protocol.KeyPhaseBit
	if ( &&  == 0) || (! &&  < -protocol.MinCoalescedPacketSize) {
		var  error
		,  = .cryptoSetup.Get1RTTSealer()
		if  != nil &&  != handshake.ErrKeysDropped &&  != handshake.ErrKeysNotYetAvailable {
			return nil, 
		}
		if  == nil { // 1-RTT
			 = .KeyPhase()
			 = .getDestConnID()
			,  = .pnManager.PeekPacketNumber(protocol.Encryption1RTT)
			 := wire.ShortHeaderLen(, )
			 = .maybeGetShortHeaderPacket(, , -, , , )
			if .length > 0 {
				 += .shortHeaderPacketLength(, , ) + protocol.ByteCount(.Overhead())
			}
		} else if .perspective == protocol.PerspectiveClient && ! { // 0-RTT packets can't contain ACK frames
			var  error
			,  = .cryptoSetup.Get0RTTSealer()
			if  != nil &&  != handshake.ErrKeysDropped &&  != handshake.ErrKeysNotYetAvailable {
				return nil, 
			}
			if  != nil {
				,  = .maybeGetAppDataPacketFor0RTT(, -, , )
				if .length > 0 {
					 += .longHeaderPacketLength(, , ) + protocol.ByteCount(.Overhead())
				}
			}
		}
	}

	if .length == 0 && .length == 0 && .length == 0 && .length == 0 {
		return nil, nil
	}

	 := getPacketBuffer()
	 := &coalescedPacket{
		buffer:         ,
		longHdrPackets: make([]*longHeaderPacket, 0, 3),
	}
	if .length > 0 {
		 := .initialPaddingLen(.frames, , )
		,  := .appendLongHeaderPacket(, , , , protocol.EncryptionInitial, , )
		if  != nil {
			return nil, 
		}
		.longHdrPackets = append(.longHdrPackets, )
	}
	if .length > 0 {
		,  := .appendLongHeaderPacket(, , , 0, protocol.EncryptionHandshake, , )
		if  != nil {
			return nil, 
		}
		.longHdrPackets = append(.longHdrPackets, )
	}
	if .length > 0 {
		,  := .appendLongHeaderPacket(, , , 0, protocol.Encryption0RTT, , )
		if  != nil {
			return nil, 
		}
		.longHdrPackets = append(.longHdrPackets, )
	} else if .length > 0 {
		,  := .appendShortHeaderPacket(, , , , , , 0, , , false, )
		if  != nil {
			return nil, 
		}
		.shortHdrPacket = &
	}
	return , nil
}

// PackAckOnlyPacket packs a packet containing only an ACK in the application data packet number space.
// It should be called after the handshake is confirmed.
func ( *packetPacker) ( protocol.ByteCount,  monotime.Time,  protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
	 := getPacketBuffer()
	,  := .appendPacket(, true, , , )
	return , , 
}

// AppendPacket packs a packet in the application data packet number space.
// It should be called after the handshake is confirmed.
func ( *packetPacker) ( *packetBuffer,  protocol.ByteCount,  monotime.Time,  protocol.Version) (shortHeaderPacket, error) {
	return .appendPacket(, false, , , )
}

func ( *packetPacker) (
	 *packetBuffer,
	 bool,
	 protocol.ByteCount,
	 monotime.Time,
	 protocol.Version,
) (shortHeaderPacket, error) {
	,  := .cryptoSetup.Get1RTTSealer()
	if  != nil {
		return shortHeaderPacket{}, 
	}
	,  := .pnManager.PeekPacketNumber(protocol.Encryption1RTT)
	 := .getDestConnID()
	 := wire.ShortHeaderLen(, )
	 := .maybeGetShortHeaderPacket(, , , , , )
	if .length == 0 {
		return shortHeaderPacket{}, errNothingToPack
	}
	 := .KeyPhase()

	return .appendShortHeaderPacket(, , , , , , 0, , , false, )
}

func ( *packetPacker) (
	 protocol.ByteCount,
	 protocol.EncryptionLevel,
	 monotime.Time,
	 bool,
	 bool,
	 protocol.Version,
) (*wire.ExtendedHeader, payload) {
	if  {
		if  := .acks.GetAckFrame(, , true);  != nil {
			 := .getLongHeader(, )
			 -= .GetLength()
			.Truncate(, )
			return , payload{ack: , length: .Length()}
		}
		return nil, payload{length: 0}
	}

	var  func() bool
	var  func( protocol.ByteCount) *wire.CryptoFrame
	//nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
	switch  {
	case protocol.EncryptionInitial:
		 = .initialStream.HasData
		 = .initialStream.PopCryptoFrame
	case protocol.EncryptionHandshake:
		 = .handshakeStream.HasData
		 = .handshakeStream.PopCryptoFrame
	}
	 := .retransmissionQueue.AckHandler()
	 := .retransmissionQueue.HasData()

	 := .acks.GetAckFrame(, , ! && !())
	var  payload
	if !() && ! &&  == nil {
		if ! {
			// nothing to send
			return nil, payload{}
		}
		 := &wire.PingFrame{}
		.frames = append(.frames, ackhandler.Frame{Frame: , Handler: emptyHandler{}})
		.length += .Length()
	}

	 := .getLongHeader(, )
	 -= .GetLength()

	if  != nil {
		.Truncate(, )
		.ack = 
		.length = .Length()
		 -= .length
	}
	if  {
		for {
			 := .retransmissionQueue.GetFrame(, , )
			if  == nil {
				break
			}
			.frames = append(.frames, ackhandler.Frame{
				Frame:   ,
				Handler: .retransmissionQueue.AckHandler(),
			})
			 := .Length()
			.length += 
			 -= 
		}
		return , 
	} else {
		for () {
			 := ()
			if  == nil {
				break
			}
			.frames = append(.frames, ackhandler.Frame{Frame: , Handler: })
			.length += .Length()
			 -= .Length()
		}
	}
	return , 
}

func ( *packetPacker) ( sealer,  protocol.ByteCount,  monotime.Time,  protocol.Version) (*wire.ExtendedHeader, payload) {
	if .perspective != protocol.PerspectiveClient {
		return nil, payload{}
	}

	 := .getLongHeader(protocol.Encryption0RTT, )
	 :=  - .GetLength() - protocol.ByteCount(.Overhead())
	return , .maybeGetAppDataPacket(, false, false, , )
}

func ( *packetPacker) (
	 handshake.ShortHeaderSealer,
	,  protocol.ByteCount,
	 bool,
	 monotime.Time,
	 protocol.Version,
) payload {
	 :=  -  - protocol.ByteCount(.Overhead())
	return .maybeGetAppDataPacket(, , true, , )
}

func ( *packetPacker) (
	 protocol.ByteCount,
	,  bool,
	 monotime.Time,
	 protocol.Version,
) payload {
	 := .composeNextPacket(, , , , )

	// check if we have anything to send
	if len(.frames) == 0 && len(.streamFrames) == 0 {
		if .ack == nil {
			return payload{}
		}
		// the packet only contains an ACK
		if .numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
			 := &wire.PingFrame{}
			.frames = append(.frames, ackhandler.Frame{Frame: })
			.length += .Length()
			.numNonAckElicitingAcks = 0
		} else {
			.numNonAckElicitingAcks++
		}
	} else {
		.numNonAckElicitingAcks = 0
	}
	return 
}

func ( *packetPacker) (
	 protocol.ByteCount,
	,  bool,
	 monotime.Time,
	 protocol.Version,
) payload {
	if  {
		if  := .acks.GetAckFrame(protocol.Encryption1RTT, , true);  != nil {
			.Truncate(, )
			return payload{ack: , length: .Length()}
		}
		return payload{}
	}

	 := .framer.HasData()
	 := .retransmissionQueue.HasData(protocol.Encryption1RTT)

	var  payload
	if  {
		if  := .acks.GetAckFrame(protocol.Encryption1RTT, , ! && !);  != nil {
			.Truncate(, )
			.ack = 
			.length += .Length()
		}
	}

	if .datagramQueue != nil {
		if  := .datagramQueue.Peek();  != nil {
			 := .Length()
			if  <= -.length { // DATAGRAM frame fits
				.frames = append(.frames, ackhandler.Frame{Frame: })
				.length += 
				.datagramQueue.Pop()
			} else if .ack == nil {
				// The DATAGRAM frame doesn't fit, and the packet doesn't contain an ACK.
				// Discard this frame. There's no point in retrying this in the next packet,
				// as it's unlikely that the available packet size will increase.
				.datagramQueue.Pop()
			}
			// If the DATAGRAM frame was too large and the packet contained an ACK, we'll try to send it out later.
		}
	}

	if .ack != nil && ! && ! {
		return 
	}

	if  {
		for {
			 :=  - .length
			if  < protocol.MinStreamFrameSize {
				break
			}
			 := .retransmissionQueue.GetFrame(protocol.Encryption1RTT, , )
			if  == nil {
				break
			}
			.frames = append(.frames, ackhandler.Frame{Frame: , Handler: .retransmissionQueue.AckHandler(protocol.Encryption1RTT)})
			.length += .Length()
		}
	}

	if  {
		var  protocol.ByteCount
		 := len(.frames)
		.frames, .streamFrames,  = .framer.Append(.frames, .streamFrames, -.length, , )
		.length += 
		// add handlers for the control frames that were added
		for  := ;  < len(.frames); ++ {
			if .frames[].Handler != nil {
				continue
			}
			switch .frames[].Frame.(type) {
			case *wire.PathChallengeFrame, *wire.PathResponseFrame:
				// Path probing is currently not supported, therefore we don't need to set the OnAcked callback yet.
				// PATH_CHALLENGE and PATH_RESPONSE are never retransmitted.
			default:
				// we might be packing a 0-RTT packet, but we need to use the 1-RTT ack handler anyway
				.frames[].Handler = .retransmissionQueue.AckHandler(protocol.Encryption1RTT)
			}
		}
	}
	return 
}

func ( *packetPacker) (
	 protocol.EncryptionLevel,
	 protocol.ByteCount,
	 bool,
	 monotime.Time,
	 protocol.Version,
) (*coalescedPacket, error) {
	if  == protocol.Encryption1RTT {
		return .packPTOProbePacket1RTT(, , , )
	}

	var  handshake.LongHeaderSealer
	//nolint:exhaustive // Probe packets are never sent for 0-RTT.
	switch  {
	case protocol.EncryptionInitial:
		var  error
		,  = .cryptoSetup.GetInitialSealer()
		if  != nil {
			return nil, 
		}
	case protocol.EncryptionHandshake:
		var  error
		,  = .cryptoSetup.GetHandshakeSealer()
		if  != nil {
			return nil, 
		}
	default:
		panic("unknown encryption level")
	}
	,  := .maybeGetCryptoPacket(
		-protocol.ByteCount(.Overhead()),
		,
		,
		,
		false,
		,
	)
	if .length == 0 {
		return nil, nil
	}
	 := getPacketBuffer()
	 := &coalescedPacket{buffer: }
	 := .longHeaderPacketLength(, , ) + protocol.ByteCount(.Overhead())
	var  protocol.ByteCount
	if  == protocol.EncryptionInitial {
		 = .initialPaddingLen(.frames, , )
	}

	,  := .appendLongHeaderPacket(, , , , , , )
	if  != nil {
		return nil, 
	}
	.longHdrPackets = []*longHeaderPacket{}
	return , nil
}

func ( *packetPacker) ( protocol.ByteCount,  bool,  monotime.Time,  protocol.Version) (*coalescedPacket, error) {
	,  := .cryptoSetup.Get1RTTSealer()
	if  != nil {
		return nil, 
	}
	 := .KeyPhase()
	 := .getDestConnID()
	,  := .pnManager.PeekPacketNumber(protocol.Encryption1RTT)
	 := wire.ShortHeaderLen(, )
	 := .maybeGetAppDataPacket(-protocol.ByteCount(.Overhead())-, false, true, , )
	if .length == 0 {
		if ! {
			return nil, nil
		}
		 := &wire.PingFrame{}
		.frames = append(.frames, ackhandler.Frame{Frame: , Handler: emptyHandler{}})
		.length += .Length()
	}
	 := getPacketBuffer()
	 := &coalescedPacket{buffer: }
	,  := .appendShortHeaderPacket(, , , , , , 0, , , false, )
	if  != nil {
		return nil, 
	}
	.shortHdrPacket = &
	return , nil
}

func ( *packetPacker) ( ackhandler.Frame,  protocol.ByteCount,  protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
	 := payload{
		frames: []ackhandler.Frame{},
		length: .Frame.Length(),
	}
	 := getPacketBuffer()
	,  := .cryptoSetup.Get1RTTSealer()
	if  != nil {
		return shortHeaderPacket{}, nil, 
	}
	 := .getDestConnID()
	,  := .pnManager.PeekPacketNumber(protocol.Encryption1RTT)
	 :=  - .shortHeaderPacketLength(, , ) - protocol.ByteCount(.Overhead())
	 := .KeyPhase()
	,  := .appendShortHeaderPacket(, , , , , , , , , true, )
	return , , 
}

func ( *packetPacker) ( protocol.ConnectionID,  []ackhandler.Frame,  protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
	,  := .pnManager.PeekPacketNumber(protocol.Encryption1RTT)
	 := getPacketBuffer()
	,  := .cryptoSetup.Get1RTTSealer()
	if  != nil {
		return shortHeaderPacket{}, nil, 
	}
	var  protocol.ByteCount
	for ,  := range  {
		 += .Frame.Length()
	}
	 := payload{
		frames: ,
		length: ,
	}
	 := protocol.MinInitialPacketSize - .shortHeaderPacketLength(, , ) - protocol.ByteCount(.Overhead())
	,  := .appendShortHeaderPacket(, , , , .KeyPhase(), , , protocol.MinInitialPacketSize, , false, )
	if  != nil {
		return shortHeaderPacket{}, nil, 
	}
	.IsPathProbePacket = true
	return , , 
}

func ( *packetPacker) ( protocol.EncryptionLevel,  protocol.Version) *wire.ExtendedHeader {
	,  := .pnManager.PeekPacketNumber()
	 := &wire.ExtendedHeader{
		PacketNumber:    ,
		PacketNumberLen: ,
	}
	.Version = 
	.SrcConnectionID = .srcConnID
	.DestConnectionID = .getDestConnID()

	//nolint:exhaustive // 1-RTT packets are not long header packets.
	switch  {
	case protocol.EncryptionInitial:
		.Type = protocol.PacketTypeInitial
		.Token = .token
	case protocol.EncryptionHandshake:
		.Type = protocol.PacketTypeHandshake
	case protocol.Encryption0RTT:
		.Type = protocol.PacketType0RTT
	}
	return 
}

func ( *packetPacker) ( *packetBuffer,  *wire.ExtendedHeader,  payload,  protocol.ByteCount,  protocol.EncryptionLevel,  sealer,  protocol.Version) (*longHeaderPacket, error) {
	var  protocol.ByteCount
	 := protocol.ByteCount(.PacketNumberLen)
	if .length < 4- {
		 = 4 -  - .length
	}
	 += 
	.Length =  + protocol.ByteCount(.Overhead()) + .length + 

	 := len(.Data)
	 := .Data[:]
	,  := .Append(, )
	if  != nil {
		return nil, 
	}
	 := protocol.ByteCount(len())

	,  = .appendPacketPayload(, , , )
	if  != nil {
		return nil, 
	}
	 = .encryptPacket(, , .PacketNumber, , )
	.Data = .Data[:len(.Data)+len()]

	if  := .pnManager.PopPacketNumber();  != .PacketNumber {
		return nil, fmt.Errorf("packetPacker BUG: Peeked and Popped packet numbers do not match: expected %d, got %d", , .PacketNumber)
	}
	return &longHeaderPacket{
		header:       ,
		ack:          .ack,
		frames:       .frames,
		streamFrames: .streamFrames,
		length:       protocol.ByteCount(len()),
	}, nil
}

func ( *packetPacker) (
	 *packetBuffer,
	 protocol.ConnectionID,
	 protocol.PacketNumber,
	 protocol.PacketNumberLen,
	 protocol.KeyPhaseBit,
	 payload,
	,  protocol.ByteCount,
	 sealer,
	 bool,
	 protocol.Version,
) (shortHeaderPacket, error) {
	var  protocol.ByteCount
	if .length < 4-protocol.ByteCount() {
		 = 4 - protocol.ByteCount() - .length
	}
	 += 

	 := len(.Data)
	 := .Data[:]
	,  := wire.AppendShortHeader(, , , , )
	if  != nil {
		return shortHeaderPacket{}, 
	}
	 := protocol.ByteCount(len())

	,  = .appendPacketPayload(, , , )
	if  != nil {
		return shortHeaderPacket{}, 
	}
	if ! {
		if  := protocol.ByteCount(len() + .Overhead());  >  {
			return shortHeaderPacket{}, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", , )
		}
	}
	 = .encryptPacket(, , , , protocol.ByteCount())
	.Data = .Data[:len(.Data)+len()]

	if  := .pnManager.PopPacketNumber(protocol.Encryption1RTT);  !=  {
		return shortHeaderPacket{}, fmt.Errorf("packetPacker BUG: Peeked and Popped packet numbers do not match: expected %d, got %d", , )
	}
	return shortHeaderPacket{
		PacketNumber:         ,
		PacketNumberLen:      ,
		KeyPhase:             ,
		StreamFrames:         .streamFrames,
		Frames:               .frames,
		Ack:                  .ack,
		Length:               protocol.ByteCount(len()),
		DestConnID:           ,
		IsPathMTUProbePacket: ,
	}, nil
}

// appendPacketPayload serializes the payload of a packet into the raw byte slice.
// It modifies the order of payload.frames.
func ( *packetPacker) ( []byte,  payload,  protocol.ByteCount,  protocol.Version) ([]byte, error) {
	 := len()
	if .ack != nil {
		var  error
		,  = .ack.Append(, )
		if  != nil {
			return nil, 
		}
	}
	if  > 0 {
		 = append(, make([]byte, )...)
	}
	// Randomize the order of the control frames.
	// This makes sure that the receiver doesn't rely on the order in which frames are packed.
	if len(.frames) > 1 {
		.rand.Shuffle(len(.frames), func(,  int) { .frames[], .frames[] = .frames[], .frames[] })
	}
	for ,  := range .frames {
		var  error
		,  = .Frame.Append(, )
		if  != nil {
			return nil, 
		}
	}
	for ,  := range .streamFrames {
		var  error
		,  = .Frame.Append(, )
		if  != nil {
			return nil, 
		}
	}

	if  := protocol.ByteCount(len()-) - ;  != .length {
		return nil, fmt.Errorf("PacketPacker BUG: payload size inconsistent (expected %d, got %d bytes)", .length, )
	}
	return , nil
}

func ( *packetPacker) ( []byte,  sealer,  protocol.PacketNumber, ,  protocol.ByteCount) []byte {
	_ = .Seal([:], [:], , [:])
	 = [:len()+.Overhead()]
	// apply header protection
	 :=  - 
	.EncryptHeader([+4:+4+16], &[0], [:])
	return 
}

func ( *packetPacker) ( []byte) {
	.token = 
}

type emptyHandler struct{}

var _ ackhandler.FrameHandler = emptyHandler{}

func (emptyHandler) (wire.Frame) {}
func (emptyHandler) (wire.Frame)  {}