package control

import (
	"bytes"
	"errors"
	"fmt"

	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/server/ctrlmessage"
	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs"
	frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
)

var errDisallowedKey = errors.New("key is not in the allowed list")

func (s *Server) isValidRequest(req ctrlmessage.SignedMessage) error {
	sign := req.GetSignature()
	if sign == nil {
		// TODO(@cthulhu-rider): #468 use "const" error
		return errors.New("missing signature")
	}

	var (
		key     = sign.GetKey()
		allowed = false
	)

	// check if key is allowed
	for i := range s.allowedKeys {
		if allowed = bytes.Equal(s.allowedKeys[i], key); allowed {
			break
		}
	}

	if !allowed {
		return errDisallowedKey
	}

	// verify signature
	binBody, err := req.ReadSignedData(nil)
	if err != nil {
		return fmt.Errorf("marshal request body: %w", err)
	}

	// TODO(@cthulhu-rider): #468 use Signature message from FrostFS API to avoid conversion
	var sigV2 refs.Signature
	sigV2.SetKey(sign.GetKey())
	sigV2.SetSign(sign.GetSign())
	sigV2.SetScheme(refs.ECDSA_SHA512)

	var sig frostfscrypto.Signature
	if err := sig.ReadFromV2(sigV2); err != nil {
		return fmt.Errorf("can't read signature: %w", err)
	}

	if !sig.Verify(binBody) {
		// TODO(@cthulhu-rider): #468 use "const" error
		return errors.New("invalid signature")
	}

	return nil
}