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

package handshake

import (
	

	
	
	
	
)

// MessageServerKeyExchange supports ECDH and PSK.
type MessageServerKeyExchange struct {
	IdentityHint []byte

	EllipticCurveType  elliptic.CurveType
	NamedCurve         elliptic.Curve
	PublicKey          []byte
	HashAlgorithm      hash.Algorithm
	SignatureAlgorithm signature.Algorithm
	Signature          []byte

	// for unmarshaling
	KeyExchangeAlgorithm types.KeyExchangeAlgorithm
}

// Type returns the Handshake Type.
func ( MessageServerKeyExchange) () Type {
	return TypeServerKeyExchange
}

// Marshal encodes the Handshake.
func ( *MessageServerKeyExchange) () ([]byte, error) { //nolint:cyclop
	var  []byte
	if .IdentityHint != nil {
		 = append([]byte{0x00, 0x00}, .IdentityHint...)
		binary.BigEndian.PutUint16(, uint16(len()-2)) //nolint:gosec //G115
	}

	if .EllipticCurveType == 0 || len(.PublicKey) == 0 {
		return , nil
	}
	 = append(, byte(.EllipticCurveType), 0x00, 0x00)
	binary.BigEndian.PutUint16([len()-2:], uint16(.NamedCurve))

	 = append(, byte(len(.PublicKey)))
	 = append(, .PublicKey...)
	switch {
	case .HashAlgorithm != hash.None && len(.Signature) == 0:
		return nil, errInvalidHashAlgorithm
	case .HashAlgorithm == hash.None && len(.Signature) > 0:
		return nil, errInvalidHashAlgorithm
	case .SignatureAlgorithm == signature.Anonymous && (.HashAlgorithm != hash.None || len(.Signature) > 0):
		return nil, errInvalidSignatureAlgorithm
	case .SignatureAlgorithm == signature.Anonymous:
		return , nil
	}

	 = append(, []byte{byte(.HashAlgorithm), byte(.SignatureAlgorithm), 0x00, 0x00}...)
	binary.BigEndian.PutUint16([len()-2:], uint16(len(.Signature))) //nolint:gosec // G115
	 = append(, .Signature...)

	return , nil
}

// Unmarshal populates the message from encoded data.
func ( *MessageServerKeyExchange) ( []byte) error { //nolint:cyclop
	switch {
	case len() < 2:
		return errBufferTooSmall
	case .KeyExchangeAlgorithm == types.KeyExchangeAlgorithmNone:
		return errCipherSuiteUnset
	}

	 := binary.BigEndian.Uint16()
	if int() <= len()-2 && .KeyExchangeAlgorithm.Has(types.KeyExchangeAlgorithmPsk) {
		.IdentityHint = append([]byte{}, [2:2+]...)
		 = [2+:]
	}
	if .KeyExchangeAlgorithm == types.KeyExchangeAlgorithmPsk {
		if len() == 0 {
			return nil
		}

		return errLengthMismatch
	}

	if !.KeyExchangeAlgorithm.Has(types.KeyExchangeAlgorithmEcdhe) {
		return errLengthMismatch
	}

	if ,  := elliptic.CurveTypes()[elliptic.CurveType([0])];  {
		.EllipticCurveType = elliptic.CurveType([0])
	} else {
		return errInvalidEllipticCurveType
	}

	if len([1:]) < 2 {
		return errBufferTooSmall
	}
	.NamedCurve = elliptic.Curve(binary.BigEndian.Uint16([1:3]))
	if ,  := elliptic.Curves()[.NamedCurve]; ! {
		return errInvalidNamedCurve
	}
	if len() < 4 {
		return errBufferTooSmall
	}

	 := int([3])
	 := 4 + 
	if len() <  {
		return errBufferTooSmall
	}
	.PublicKey = append([]byte{}, [4:]...)

	// Anon connection doesn't contains hashAlgorithm, signatureAlgorithm, signature
	if len() ==  {
		return nil
	} else if len() <=  {
		return errBufferTooSmall
	}

	.HashAlgorithm = hash.Algorithm([])
	if ,  := hash.Algorithms()[.HashAlgorithm]; ! {
		return errInvalidHashAlgorithm
	}
	++
	if len() <=  {
		return errBufferTooSmall
	}
	.SignatureAlgorithm = signature.Algorithm([])
	if ,  := signature.Algorithms()[.SignatureAlgorithm]; ! {
		return errInvalidSignatureAlgorithm
	}
	++
	if len() < +2 {
		return errBufferTooSmall
	}
	 := int(binary.BigEndian.Uint16([:]))
	 += 2
	if len() < + {
		return errBufferTooSmall
	}
	.Signature = append([]byte{}, [:+]...)

	return nil
}