package handshake

import (
	"encoding/binary"

	"github.com/pion/dtls/v2/pkg/crypto/hash"
	"github.com/pion/dtls/v2/pkg/crypto/signature"
)

// MessageCertificateVerify provide explicit verification of a
// client certificate.
//
// https://tools.ietf.org/html/rfc5246#section-7.4.8
type MessageCertificateVerify struct {
	HashAlgorithm      hash.Algorithm
	SignatureAlgorithm signature.Algorithm
	Signature          []byte
}

const handshakeMessageCertificateVerifyMinLength = 4

// Type returns the Handshake Type
func (m MessageCertificateVerify) Type() Type {
	return TypeCertificateVerify
}

// Marshal encodes the Handshake
func (m *MessageCertificateVerify) Marshal() ([]byte, error) {
	out := make([]byte, 1+1+2+len(m.Signature))

	out[0] = byte(m.HashAlgorithm)
	out[1] = byte(m.SignatureAlgorithm)
	binary.BigEndian.PutUint16(out[2:], uint16(len(m.Signature)))
	copy(out[4:], m.Signature)
	return out, nil
}

// Unmarshal populates the message from encoded data
func (m *MessageCertificateVerify) Unmarshal(data []byte) error {
	if len(data) < handshakeMessageCertificateVerifyMinLength {
		return errBufferTooSmall
	}

	m.HashAlgorithm = hash.Algorithm(data[0])
	if _, ok := hash.Algorithms()[m.HashAlgorithm]; !ok {
		return errInvalidHashAlgorithm
	}

	m.SignatureAlgorithm = signature.Algorithm(data[1])
	if _, ok := signature.Algorithms()[m.SignatureAlgorithm]; !ok {
		return errInvalidSignatureAlgorithm
	}

	signatureLength := int(binary.BigEndian.Uint16(data[2:]))
	if (signatureLength + 4) != len(data) {
		return errBufferTooSmall
	}

	m.Signature = append([]byte{}, data[4:]...)
	return nil
}
