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

package dtls

import (
	

	
	
	
	
	
	
)

func flight1Parse(
	 context.Context,
	 flightConn,
	 *State,
	 *handshakeCache,
	 *handshakeConfig,
) (flightVal, *alert.Alert, error) {
	// HelloVerifyRequest can be skipped by the server,
	// so allow ServerHello during flight1 also
	, ,  := .fullPullMap(.handshakeRecvSequence, .cipherSuite,
		handshakeCachePullRule{handshake.TypeHelloVerifyRequest, .initialEpoch, false, true},
		handshakeCachePullRule{handshake.TypeServerHello, .initialEpoch, false, true},
	)
	if ! {
		// No valid message received. Keep reading
		return 0, nil, nil
	}

	if ,  := [handshake.TypeServerHello];  {
		// Flight1 and flight2 were skipped.
		// Parse as flight3.
		return flight3Parse(, , , , )
	}

	if ,  := [handshake.TypeHelloVerifyRequest].(*handshake.MessageHelloVerifyRequest);  {
		// DTLS 1.2 clients must not assume that the server will use the protocol version
		// specified in HelloVerifyRequest message. RFC 6347 Section 4.2.1
		if !.Version.Equal(protocol.Version1_0) && !.Version.Equal(protocol.Version1_2) {
			return 0, &alert.Alert{Level: alert.Fatal, Description: alert.ProtocolVersion}, errUnsupportedProtocolVersion
		}
		.cookie = append([]byte{}, .Cookie...)
		.handshakeRecvSequence = 

		return flight3, nil, nil
	}

	return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
}

//nolint:cyclop
func flight1Generate(
	 flightConn,
	 *State,
	 *handshakeCache,
	 *handshakeConfig,
) ([]*packet, *alert.Alert, error) {
	var  uint16
	.localEpoch.Store()
	.remoteEpoch.Store()
	.namedCurve = defaultNamedCurve
	.cookie = nil

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

	if .helloRandomBytesGenerator != nil {
		.localRandom.RandomBytes = .helloRandomBytesGenerator()
	}

	 := []extension.Extension{
		&extension.SupportedSignatureAlgorithms{
			SignatureHashAlgorithms: .localSignatureSchemes,
		},
		&extension.RenegotiationInfo{
			RenegotiatedConnection: 0,
		},
	}

	var  bool
	for ,  := range .localCipherSuites {
		if .ECC() {
			 = true

			break
		}
	}

	if  {
		 = append(, []extension.Extension{
			&extension.SupportedEllipticCurves{
				EllipticCurves: .ellipticCurves,
			},
			&extension.SupportedPointFormats{
				PointFormats: []elliptic.CurvePointFormat{elliptic.CurvePointFormatUncompressed},
			},
		}...)
	}

	if len(.localSRTPProtectionProfiles) > 0 {
		 = append(, &extension.UseSRTP{
			ProtectionProfiles:  .localSRTPProtectionProfiles,
			MasterKeyIdentifier: .localSRTPMasterKeyIdentifier,
		})
	}

	if .extendedMasterSecret == RequestExtendedMasterSecret ||
		.extendedMasterSecret == RequireExtendedMasterSecret {
		 = append(, &extension.UseExtendedMasterSecret{
			Supported: true,
		})
	}

	if len(.serverName) > 0 {
		 = append(, &extension.ServerName{ServerName: .serverName})
	}

	if len(.supportedProtocols) > 0 {
		 = append(, &extension.ALPN{ProtocolNameList: .supportedProtocols})
	}

	if .sessionStore != nil {
		.log.Tracef("[handshake] try to resume session")
		if ,  := .sessionStore.Get(.sessionKey());  != nil {
			return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, 
		} else if .ID != nil {
			.log.Tracef("[handshake] get saved session: %x", .ID)

			.SessionID = .ID
			.masterSecret = .Secret
		}
	}

	// If we have a connection ID generator, use it. The CID may be zero length,
	// in which case we are just requesting that the server send us a CID to
	// use.
	if .connectionIDGenerator != nil {
		.setLocalConnectionID(.connectionIDGenerator())
		// The presence of a generator indicates support for connection IDs. We
		// use the presence of a non-nil local CID in flight 3 to determine
		// whether we send a CID in the second ClientHello, so we convert any
		// nil CID returned by a generator to []byte{}.
		if .getLocalConnectionID() == nil {
			.setLocalConnectionID([]byte{})
		}
		 = append(, &extension.ConnectionID{CID: .getLocalConnectionID()})
	}

	 := &handshake.MessageClientHello{
		Version:            protocol.Version1_2,
		SessionID:          .SessionID,
		Cookie:             .cookie,
		Random:             .localRandom,
		CipherSuiteIDs:     cipherSuiteIDs(.localCipherSuites),
		CompressionMethods: defaultCompressionMethods(),
		Extensions:         ,
	}

	var  handshake.Handshake

	if .clientHelloMessageHook != nil {
		 = handshake.Handshake{Message: .clientHelloMessageHook(*)}
	} else {
		 = handshake.Handshake{Message: }
	}

	return []*packet{
		{
			record: &recordlayer.RecordLayer{
				Header: recordlayer.Header{
					Version: protocol.Version1_2,
				},
				Content: &,
			},
		},
	}, nil, nil
}