package control

import (
	"crypto/ecdsa"
	"errors"

	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
	internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
	controlSvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/server"
	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
	frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
	"github.com/spf13/cobra"
)

const (
	irFlagNameVUB = "vub"
)

func initControlFlags(cmd *cobra.Command) {
	ff := cmd.Flags()
	ff.StringP(commonflags.WalletPath, commonflags.WalletPathShorthand, commonflags.WalletPathDefault, commonflags.WalletPathUsage)
	ff.StringP(commonflags.Account, commonflags.AccountShorthand, commonflags.AccountDefault, commonflags.AccountUsage)
	ff.String(controlRPC, controlRPCDefault, controlRPCUsage)
	ff.DurationP(commonflags.Timeout, commonflags.TimeoutShorthand, commonflags.TimeoutDefault, commonflags.TimeoutUsage)
}

func initControlIRFlags(cmd *cobra.Command) {
	initControlFlags(cmd)

	ff := cmd.Flags()
	ff.Uint32(irFlagNameVUB, 0, "Valid until block value for notary transaction")
}

func signRequest(cmd *cobra.Command, pk *ecdsa.PrivateKey, req controlSvc.SignedMessage) {
	err := controlSvc.SignMessage(pk, req)
	commonCmd.ExitOnErr(cmd, "could not sign request: %w", err)
}

func verifyResponse(cmd *cobra.Command,
	sigControl interface {
		GetKey() []byte
		GetSign() []byte
	},
	body interface {
		StableMarshal([]byte) []byte
	},
) {
	if sigControl == nil {
		commonCmd.ExitOnErr(cmd, "", errors.New("missing response signature"))
	}

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

	var sig frostfscrypto.Signature
	commonCmd.ExitOnErr(cmd, "can't read signature: %w", sig.ReadFromV2(sigV2))

	if !sig.Verify(body.StableMarshal(nil)) {
		commonCmd.ExitOnErr(cmd, "", errors.New("invalid response signature"))
	}
}

func getClient(cmd *cobra.Command, pk *ecdsa.PrivateKey) *client.Client {
	return internalclient.GetSDKClientByFlag(cmd, pk, controlRPC)
}