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

package dtls

import (
	
	

	
	
	
	
	
	
)

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

	var  *handshake.MessageFinished
	if ,  = [handshake.TypeFinished].(*handshake.MessageFinished); ! {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, nil
	}

	 := .pullAndMerge(
		handshakeCachePullRule{handshake.TypeClientHello, .initialEpoch, true, false},
		handshakeCachePullRule{handshake.TypeServerHello, .initialEpoch, false, false},
		handshakeCachePullRule{handshake.TypeFinished, .initialEpoch + 1, false, false},
	)

	,  := prf.VerifyDataClient(.masterSecret, , .cipherSuite.HashFunc())
	if  != nil {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, 
	}
	if !bytes.Equal(, .VerifyData) {
		return 0, &alert.Alert{Level: alert.Fatal, Description: alert.HandshakeFailure}, errVerifyDataMismatch
	}

	// Other party may re-transmit the last flight. Keep state to be flight4b.
	return flight4b, nil, nil
}

//nolint:cyclop
func flight4bGenerate(
	 flightConn,
	 *State,
	 *handshakeCache,
	 *handshakeConfig,
) ([]*packet, *alert.Alert, error) {
	var  []*packet

	 := []extension.Extension{&extension.RenegotiationInfo{
		RenegotiatedConnection: 0,
	}}
	if (.extendedMasterSecret == RequestExtendedMasterSecret ||
		.extendedMasterSecret == RequireExtendedMasterSecret) && .extendedMasterSecret {
		 = append(, &extension.UseExtendedMasterSecret{
			Supported: true,
		})
	}
	if .getSRTPProtectionProfile() != 0 {
		 = append(, &extension.UseSRTP{
			ProtectionProfiles:  []SRTPProtectionProfile{.getSRTPProtectionProfile()},
			MasterKeyIdentifier: .localSRTPMasterKeyIdentifier,
		})
	}

	,  := extension.ALPNProtocolSelection(.supportedProtocols, .peerSupportedProtocols)
	if  != nil {
		return nil, &alert.Alert{Level: alert.Fatal, Description: alert.NoApplicationProtocol}, 
	}
	if  != "" {
		 = append(, &extension.ALPN{
			ProtocolNameList: []string{},
		})
		.NegotiatedProtocol = 
	}

	 := uint16(.cipherSuite.ID())
	var  handshake.Handshake

	 := &handshake.MessageServerHello{
		Version:           protocol.Version1_2,
		Random:            .localRandom,
		SessionID:         .SessionID,
		CipherSuiteID:     &,
		CompressionMethod: defaultCompressionMethods()[0],
		Extensions:        ,
	}

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

	.Header.MessageSequence = uint16(.handshakeSendSequence) //nolint:gosec // G115

	if len(.localVerifyData) == 0 {
		 := .pullAndMerge(
			handshakeCachePullRule{handshake.TypeClientHello, .initialEpoch, true, false},
		)
		,  := .Marshal()
		if  != nil {
			return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, 
		}
		 = append(, ...)

		.localVerifyData,  = prf.VerifyDataServer(.masterSecret, , .cipherSuite.HashFunc())
		if  != nil {
			return nil, &alert.Alert{Level: alert.Fatal, Description: alert.InternalError}, 
		}
	}

	 = append(,
		&packet{
			record: &recordlayer.RecordLayer{
				Header: recordlayer.Header{
					Version: protocol.Version1_2,
				},
				Content: &,
			},
		},
		&packet{
			record: &recordlayer.RecordLayer{
				Header: recordlayer.Header{
					Version: protocol.Version1_2,
				},
				Content: &protocol.ChangeCipherSpec{},
			},
		},
		&packet{
			record: &recordlayer.RecordLayer{
				Header: recordlayer.Header{
					Version: protocol.Version1_2,
					Epoch:   1,
				},
				Content: &handshake.Handshake{
					Message: &handshake.MessageFinished{
						VerifyData: .localVerifyData,
					},
				},
			},
			shouldEncrypt:            true,
			resetLocalSequenceNumber: true,
		},
	)

	return , nil, nil
}