/*
Copyright SecureKey Technologies Inc. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package signingmgr

import (
	fbccsp "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp"
	cspx509 "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp/x509"
	logging "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/sdkpatch/logbridge"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/core"
	"github.com/hyperledger/fabric-sdk-go/pkg/core/cryptosuite"
	"github.com/pkg/errors"
)

// SigningManager is used for signing objects with private key
type SigningManager struct {
	cryptoProvider core.CryptoSuite
	hashOpts       core.HashOpts
	//signerOpts     core.SignerOpts
}

// New Constructor for a signing manager.
// @param {BCCSP} cryptoProvider - crypto provider
// @param {Config} config - configuration provider
// @returns {SigningManager} new signing manager
func New(cryptoProvider core.CryptoSuite) (*SigningManager, error) {
	return &SigningManager{cryptoProvider: cryptoProvider, hashOpts: cryptosuite.GetSHAOpts()}, nil
}

var mspIdentityLogger = logging.MustGetLogger("fab.signingmgr")

// Sign will sign the given object using provided key
//func (mgr *SigningManager) Sign(object []byte, key core.Key) ([]byte, error) {
//
//	if len(object) == 0 {
//		return nil, errors.New("object (to sign) required")
//	}
//
//	if key == nil {
//		return nil, errors.New("key (for signing) required")
//	}
//
//	digest, err := mgr.cryptoProvider.Hash(object, mgr.hashOpts)
//	if err != nil {
//		return nil, err
//	}
//	signature, err := mgr.cryptoProvider.Sign(key, digest, mgr.signerOpts)
//	if err != nil {
//		return nil, err
//	}
//	return signature, nil
//}

// Sign will sign the given object using provided key
func (mgr *SigningManager) Sign(object []byte, key core.Key) ([]byte, error) {

	if len(object) == 0 {
		return nil, errors.New("object (to sign) required")
	}

	if key == nil {
		return nil, errors.New("key (for signing) required")
	}

	var digest []byte
	var err error
	var signerOption fbccsp.SignerOpts

	if key.Algorithm() == fbccsp.SM2 {
		digest = object
		signerOption = fbccsp.SignerOpts(cspx509.SM3)
	} else {
		digest, err = mgr.cryptoProvider.Hash(object, mgr.hashOpts)
		if err != nil {
			return nil, errors.WithMessage(err, "failed computing digest")
		}
		signerOption = nil
	}

	if mspIdentityLogger.IsEnabledFor(logging.DEBUG) {
		mspIdentityLogger.Infof("Sign: sig type = %s", key.Algorithm())
	}

	if len(object) < 32 {
		mspIdentityLogger.Debugf("Sign: plaintext: %X \n", object)
	} else {
		mspIdentityLogger.Debugf("Sign: plaintext: %X...%X \n", object[0:16], object[len(object)-16:])
	}
	mspIdentityLogger.Debugf("Sign: digest: %X \n", digest)

	signature, err := mgr.cryptoProvider.Sign(key, digest, signerOption)
	if err != nil {
		return nil, err
	}
	return signature, nil
}
