// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package dtls

import (
	
	

	
	
	
	
	
)

//nolint:cyclop
func flight0Parse(
	 context.Context,
	 flightConn,
	 *State,
	 *handshakeCache,
	 *handshakeConfig,
) (flightVal, *alert.Alert, error) {
	, ,  := .fullPullMap(0, .cipherSuite,
		handshakeCachePullRule{handshake.TypeClientHello, .initialEpoch, true, false},
	)
	if ! {
		// No valid message received. Keep reading
		return 0, nil, nil
	}

	// Connection Identifiers must be negotiated afresh on session resumption.
	// https://datatracker.ietf.org/doc/html/rfc9146#name-the-connection_id-extension
	.setLocalConnectionID(nil)
	.remoteConnectionID = nil

	.handshakeRecvSequence = 

	var  *handshake.MessageClientHello

	// Validate type
	if ,  = [handshake.TypeClientHello].(*handshake.MessageClientHello); ! {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
	}

	if !.Version.Equal(protocol.Version1_2) {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
	}

	.remoteRandom = .Random

	 := []CipherSuite{}
	for ,  := range .CipherSuiteIDs {
		if  := cipherSuiteForID(CipherSuiteID(), .customCipherSuites);  != nil {
			 = append(, )
		}
	}

	if .cipherSuite,  = findMatchingCipherSuite(, .localCipherSuites); ! {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errCipherSuiteNoIntersection
	}

	for ,  := range .Extensions {
		switch ext := .(type) {
		case *extension.SupportedEllipticCurves:
			if len(.EllipticCurves) == 0 {
				return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errNoSupportedEllipticCurves
			}
			.namedCurve = .EllipticCurves[0]
		case *extension.UseSRTP:
			,  := findMatchingSRTPProfile(.ProtectionProfiles, .localSRTPProtectionProfiles)
			if ! {
				return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerNoMatchingSRTPProfile
			}
			.setSRTPProtectionProfile()
			.remoteSRTPMasterKeyIdentifier = .MasterKeyIdentifier
		case *extension.UseExtendedMasterSecret:
			if .extendedMasterSecret != DisableExtendedMasterSecret {
				.extendedMasterSecret = true
			}
		case *extension.ServerName:
			.serverName = .ServerName // remote server name
		case *extension.ALPN:
			.peerSupportedProtocols = .ProtocolNameList
		case *extension.ConnectionID:
			// Only set connection ID to be sent if server supports connection
			// IDs.
			if .connectionIDGenerator != nil {
				.remoteConnectionID = .CID
			}
		}
	}

	// If the client doesn't support connection IDs, the server should not
	// expect one to be sent.
	if .remoteConnectionID == nil {
		.setLocalConnectionID(nil)
	}

	if .extendedMasterSecret == RequireExtendedMasterSecret && !.extendedMasterSecret {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerRequiredButNoClientEMS
	}

	if .localKeypair == nil {
		var  error
		.localKeypair,  = elliptic.GenerateKeypair(.namedCurve)
		if  != nil {
			return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, 
		}
	}

	 := flight2

	if .insecureSkipHelloVerify {
		 = flight4
	}

	return handleHelloResume(.SessionID, , , )
}

func handleHelloResume(
	 []byte,
	 *State,
	 *handshakeConfig,
	 flightVal,
) (flightVal, *alert.Alert, error) {
	if len() > 0 && .sessionStore != nil {
		if ,  := .sessionStore.Get();  != nil {
			return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, 
		} else if .ID != nil {
			.log.Tracef("[handshake] resume session: %x", )

			.SessionID = 
			.masterSecret = .Secret

			if  := .initCipherSuite();  != nil {
				return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, 
			}

			 := .localRandom.MarshalFixed()
			.writeKeyLog(keyLogLabelTLS12, [:], .masterSecret)

			return flight4b, nil, nil
		}
	}

	return , nil, nil
}

func flight0Generate(
	 flightConn,
	 *State,
	 *handshakeCache,
	 *handshakeConfig,
) ([]*packet, *alert.Alert, error) {
	// Initialize
	if !.insecureSkipHelloVerify {
		.cookie = make([]byte, cookieLength)
		if ,  := rand.Read(.cookie);  != nil {
			return nil, nil, 
		}
	}

	var  uint16
	.localEpoch.Store()
	.remoteEpoch.Store()
	.namedCurve = defaultNamedCurve

	if  := .localRandom.Populate();  != nil {
		return nil, nil, 
	}

	return nil, nil, nil
}