package wire

import (
	
	
	
	

	
	
)

// ParseConnectionID parses the destination connection ID of a packet.
func ( []byte,  int) (protocol.ConnectionID, error) {
	if len() == 0 {
		return protocol.ConnectionID{}, io.EOF
	}
	if !IsLongHeaderPacket([0]) {
		if len() < +1 {
			return protocol.ConnectionID{}, io.EOF
		}
		return protocol.ParseConnectionID([1 : 1+]), nil
	}
	if len() < 6 {
		return protocol.ConnectionID{}, io.EOF
	}
	 := int([5])
	if  > protocol.MaxConnIDLen {
		return protocol.ConnectionID{}, protocol.ErrInvalidConnectionIDLen
	}
	if len() < 6+ {
		return protocol.ConnectionID{}, io.EOF
	}
	return protocol.ParseConnectionID([6 : 6+]), nil
}

// ParseArbitraryLenConnectionIDs parses the most general form of a Long Header packet,
// using only the version-independent packet format as described in Section 5.1 of RFC 8999:
// https://datatracker.ietf.org/doc/html/rfc8999#section-5.1.
// This function should only be called on Long Header packets for which we don't support the version.
func ( []byte) ( int, ,  protocol.ArbitraryLenConnectionID,  error) {
	 := len()
	if len() < 6 {
		return 0, nil, nil, io.EOF
	}
	 = [5:] // skip first byte and version field
	 := [0]
	 = [1:]
	 := make(protocol.ArbitraryLenConnectionID, )
	if len() < int()+1 {
		return 0, nil, nil, io.EOF
	}
	copy(, )
	 = [:]
	 := [0]
	 = [1:]
	if len() < int() {
		return 0, nil, nil, io.EOF
	}
	 := make(protocol.ArbitraryLenConnectionID, )
	copy(, )
	return  - len() + int(), , , nil
}

func ( byte) bool {
	return &0x40 > 0
}

// IsLongHeaderPacket says if this is a Long Header packet
func ( byte) bool {
	return &0x80 > 0
}

// ParseVersion parses the QUIC version.
// It should only be called for Long Header packets (Short Header packets don't contain a version number).
func ( []byte) (protocol.Version, error) {
	if len() < 5 {
		return 0, io.EOF
	}
	return protocol.Version(binary.BigEndian.Uint32([1:5])), nil
}

// IsVersionNegotiationPacket says if this is a version negotiation packet
func ( []byte) bool {
	if len() < 5 {
		return false
	}
	return IsLongHeaderPacket([0]) && [1] == 0 && [2] == 0 && [3] == 0 && [4] == 0
}

// Is0RTTPacket says if this is a 0-RTT packet.
// A packet sent with a version we don't understand can never be a 0-RTT packet.
func ( []byte) bool {
	if len() < 5 {
		return false
	}
	if !IsLongHeaderPacket([0]) {
		return false
	}
	 := protocol.Version(binary.BigEndian.Uint32([1:5]))
	//nolint:exhaustive // We only need to test QUIC versions that we support.
	switch  {
	case protocol.Version1:
		return [0]>>4&0b11 == 0b01
	case protocol.Version2:
		return [0]>>4&0b11 == 0b10
	default:
		return false
	}
}

var ErrUnsupportedVersion = errors.New("unsupported version")

// The Header is the version independent part of the header
type Header struct {
	typeByte byte
	Type     protocol.PacketType

	Version          protocol.Version
	SrcConnectionID  protocol.ConnectionID
	DestConnectionID protocol.ConnectionID

	Length protocol.ByteCount

	Token []byte

	parsedLen protocol.ByteCount // how many bytes were read while parsing this header
}

// ParsePacket parses a long header packet.
// The packet is cut according to the length field.
// If we understand the version, the packet is parsed up unto the packet number.
// Otherwise, only the invariant part of the header is parsed.
func ( []byte) (*Header, []byte, []byte, error) {
	if len() == 0 || !IsLongHeaderPacket([0]) {
		return nil, nil, nil, errors.New("not a long header packet")
	}
	,  := parseHeader()
	if  != nil {
		if errors.Is(, ErrUnsupportedVersion) {
			return , nil, nil, 
		}
		return nil, nil, nil, 
	}
	if protocol.ByteCount(len()) < .ParsedLen()+.Length {
		return nil, nil, nil, fmt.Errorf("packet length (%d bytes) is smaller than the expected length (%d bytes)", len()-int(.ParsedLen()), .Length)
	}
	 := int(.ParsedLen() + .Length)
	return , [:], [:], nil
}

// ParseHeader parses the header:
// * if we understand the version: up to the packet number
// * if not, only the invariant part of the header
func parseHeader( []byte) (*Header, error) {
	if len() == 0 {
		return nil, io.EOF
	}
	 := [0]

	 := &Header{typeByte: }
	,  := .parseLongHeader([1:])
	.parsedLen = protocol.ByteCount() + 1
	return , 
}

func ( *Header) ( []byte) (int, error) {
	 := len()
	if len() < 5 {
		return 0, io.EOF
	}
	.Version = protocol.Version(binary.BigEndian.Uint32([:4]))
	if .Version != 0 && .typeByte&0x40 == 0 {
		return  - len(), errors.New("not a QUIC packet")
	}
	 := int([4])
	if  > protocol.MaxConnIDLen {
		return  - len(), protocol.ErrInvalidConnectionIDLen
	}
	 = [5:]
	if len() < +1 {
		return  - len(), io.EOF
	}
	.DestConnectionID = protocol.ParseConnectionID([:])
	 := int([])
	if  > protocol.MaxConnIDLen {
		return  - len(), protocol.ErrInvalidConnectionIDLen
	}
	 = [+1:]
	if len() <  {
		return  - len(), io.EOF
	}
	.SrcConnectionID = protocol.ParseConnectionID([:])
	 = [:]
	if .Version == 0 { // version negotiation packet
		return  - len(), nil
	}
	// If we don't understand the version, we have no idea how to interpret the rest of the bytes
	if !protocol.IsSupportedVersion(protocol.SupportedVersions, .Version) {
		return  - len(), ErrUnsupportedVersion
	}

	if .Version == protocol.Version2 {
		switch .typeByte >> 4 & 0b11 {
		case 0b00:
			.Type = protocol.PacketTypeRetry
		case 0b01:
			.Type = protocol.PacketTypeInitial
		case 0b10:
			.Type = protocol.PacketType0RTT
		case 0b11:
			.Type = protocol.PacketTypeHandshake
		}
	} else {
		switch .typeByte >> 4 & 0b11 {
		case 0b00:
			.Type = protocol.PacketTypeInitial
		case 0b01:
			.Type = protocol.PacketType0RTT
		case 0b10:
			.Type = protocol.PacketTypeHandshake
		case 0b11:
			.Type = protocol.PacketTypeRetry
		}
	}

	if .Type == protocol.PacketTypeRetry {
		 := len() - 16
		if  <= 0 {
			return  - len(), io.EOF
		}
		.Token = make([]byte, )
		copy(.Token, [:])
		return  - len() +  + 16, nil
	}

	if .Type == protocol.PacketTypeInitial {
		, ,  := quicvarint.Parse()
		if  != nil {
			return  - len(), 
		}
		 = [:]
		if  > uint64(len()) {
			return  - len(), io.EOF
		}
		.Token = make([]byte, )
		copy(.Token, [:])
		 = [:]
	}

	, ,  := quicvarint.Parse()
	if  != nil {
		return 0, 
	}
	.Length = protocol.ByteCount()
	return  - len() + , nil
}

// ParsedLen returns the number of bytes that were consumed when parsing the header
func ( *Header) () protocol.ByteCount {
	return .parsedLen
}

// ParseExtended parses the version dependent part of the header.
// The Reader has to be set such that it points to the first byte of the header.
func ( *Header) ( []byte) (*ExtendedHeader, error) {
	 := .toExtendedHeader()
	,  := .parse()
	if  != nil {
		return nil, 
	}
	if ! {
		return , ErrInvalidReservedBits
	}
	return , nil
}

func ( *Header) () *ExtendedHeader {
	return &ExtendedHeader{Header: *}
}

// PacketType is the type of the packet, for logging purposes
func ( *Header) () string {
	return .Type.String()
}

func readPacketNumber( []byte,  protocol.PacketNumberLen) (protocol.PacketNumber, error) {
	var  protocol.PacketNumber
	switch  {
	case protocol.PacketNumberLen1:
		 = protocol.PacketNumber([0])
	case protocol.PacketNumberLen2:
		 = protocol.PacketNumber(binary.BigEndian.Uint16([:2]))
	case protocol.PacketNumberLen3:
		 = protocol.PacketNumber(uint32([2]) + uint32([1])<<8 + uint32([0])<<16)
	case protocol.PacketNumberLen4:
		 = protocol.PacketNumber(binary.BigEndian.Uint32([:4]))
	default:
		return 0, fmt.Errorf("invalid packet number length: %d", )
	}
	return , nil
}