/*
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.

SPDX-License-Identifier: Apache-2.0
*/

package chain

import (
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"

	"chainmaker.org/chainmaker/common/v2/crypto/x509"
	chainmaker_sdk_go "chainmaker.org/chainmaker/sdk-go/v2"
)

// NodeConf add next time
// @Description:
type NodeConf struct {
	Url         string
	EnableTls   bool
	TlsHostName string
	UserTlsCert string
	UserTlsKey  string
}

// createSDKClient 创建 sdk client
//
//	@Description:
//	@param nodeConfs
//	@param chainId
//	@param chainMode
//	@param userKey
//	@param userCert
//	@param hashMethod
//	@return *chainmaker_sdk_go.ChainClient
//	@return error
func createSDKClient(nodeConfs []NodeConf, chainId, chainMode, signKey, signCert,
	hashMethod, orgId, caCert string) (sdkClient *chainmaker_sdk_go.ChainClient, err error) {
	rpcConf := chainmaker_sdk_go.NewRPCClientConfig(
		chainmaker_sdk_go.WithRPCClientGetTxTimeout(60),
		chainmaker_sdk_go.WithRPCClientSendTxTimeout(60),
		chainmaker_sdk_go.WithRPCClientMaxReceiveMessageSize(100),
		chainmaker_sdk_go.WithRPCClientMaxSendMessageSize(100),
	)

	cryptoConf := chainmaker_sdk_go.NewCryptoConfig(
		chainmaker_sdk_go.WithHashAlgo(hashMethod),
	)

	sdkClientOpts := []chainmaker_sdk_go.ChainClientOption{
		chainmaker_sdk_go.WithChainClientChainId(chainId),
		chainmaker_sdk_go.WithCryptoConfig(cryptoConf),
		chainmaker_sdk_go.WithRetryInterval(500),
		chainmaker_sdk_go.WithRetryLimit(20),
		chainmaker_sdk_go.WithEnableNormalKey(false),
		chainmaker_sdk_go.WithRPCClientConfig(rpcConf),
	}

	// 解码 ca cert
	caStr, err := base64.StdEncoding.DecodeString(caCert)
	if err != nil {
		return nil, fmt.Errorf("failed to base64 decode caCert,err: %v", err)
	}

	// 添加多个 node 配置
	userTlsCert := ""
	userTlsKey := ""
	for _, n := range nodeConfs {
		nodeConf := chainmaker_sdk_go.NewNodeConfig(
			chainmaker_sdk_go.WithNodeAddr(n.Url),
			chainmaker_sdk_go.WithNodeConnCnt(10),
			chainmaker_sdk_go.WithNodeUseTLS(n.EnableTls),
			chainmaker_sdk_go.WithNodeTLSHostName(n.TlsHostName),

			// 如果是开启 tls,必须传 CaCert
			chainmaker_sdk_go.WithNodeCACerts([]string{string(caStr)}),
		)

		sdkClientOpts = append(sdkClientOpts, chainmaker_sdk_go.AddChainClientNodeConfig(nodeConf))

		// 任意取一个节点的 userTlsCert 和 userTlsKey
		if n.UserTlsCert != "" && n.UserTlsKey != "" {
			userTlsCert = n.UserTlsCert
			userTlsKey = n.UserTlsKey
		}
	}

	key, err := base64.StdEncoding.DecodeString(signKey)
	if err != nil {
		return nil, fmt.Errorf("failed to base64 decode signKey,err: %v", err)
	}

	switch chainMode {
	case KEY_MODE_PK:

		sdkClientOpts = append(sdkClientOpts,
			chainmaker_sdk_go.WithAuthType("public"),

			// 这里是用于签名的
			chainmaker_sdk_go.WithUserSignKeyBytes(key),
		)
	case KEY_MODE_CERT:
		userKey, err1 := base64.StdEncoding.DecodeString(userTlsKey)
		if err1 != nil {
			return nil, fmt.Errorf("failed to base64 decode userTlsKey,err: %v", err1)
		}

		userCert, err1 := base64.StdEncoding.DecodeString(userTlsCert)
		if err1 != nil {
			return nil, fmt.Errorf("failed to base64 decode userTlsCert,err: %v", err1)
		}

		sCert, err1 := base64.StdEncoding.DecodeString(signCert)
		if err1 != nil {
			return nil, fmt.Errorf("failed to base64 decode signCert,err: %v", err1)
		}

		sdkClientOpts = append(sdkClientOpts,
			chainmaker_sdk_go.WithAuthType("permissionedwithcert"),
			chainmaker_sdk_go.WithChainClientOrgId(orgId),

			// 这两个参数是证书模式下,用于验证节点端证书有效性的,并不是签名用的
			chainmaker_sdk_go.WithUserKeyBytes(userKey),
			chainmaker_sdk_go.WithUserCrtBytes(userCert),

			// 这里是用于签名的
			chainmaker_sdk_go.WithUserSignKeyBytes(key),
			chainmaker_sdk_go.WithUserSignCrtBytes(sCert),
		)
	}

	if signKey != "" {
		sdkClient, err = chainmaker_sdk_go.NewChainClient(sdkClientOpts...)
		if err != nil {
			return nil, fmt.Errorf("failed to new sdk client,err: %v", err)
		}
	} else {
		sdkClient, err = chainmaker_sdk_go.NewChainClientWithoutKey(sdkClientOpts...)
		if err != nil {
			return nil, fmt.Errorf("failed to new sdk client without sign key,err: %v", err)
		}
	}

	return sdkClient, nil
}

// CreateSDKClient 创建 sdk client
//
//	@Description:
//	@param nodeConfs
//	@param chainId
//	@param chainMode
//	@param userKey
//	@param userCert
//	@param hashMethod
//	@return *chainmaker_sdk_go.ChainClient
//	@return error
func CreateSDKClient(nodeConfs []NodeConf, chainId, chainMode, signKey, signCert,
	hashMethod, orgId, caCert string) (*chainmaker_sdk_go.ChainClient, error) {
	return createSDKClient(nodeConfs, chainId, chainMode, signKey, signCert, hashMethod, orgId, caCert)
}

// CreateSDKClientWithoutKey  创建 sdk client 不带签名 key
//
//	@Description:
//	@param nodeConfs
//	@param chainId
//	@param chainMode
//	@param hashMethod
//	@return *chainmaker_sdk_go.ChainClient
//	@return error
func CreateSDKClientWithoutKey(nodeConfs []NodeConf, chainId,
	chainMode, orgId, caCert string) (*chainmaker_sdk_go.ChainClient, error) {
	return createSDKClient(nodeConfs, chainId, chainMode, "", "", "", orgId, caCert)
}

// GetOrgId  获取证书中的 org id
//
//	@Description:
//	@param cert
//	@return string
//	@return error
func GetOrgId(cert []byte) (string, error) {
	pemBlock, _ := pem.Decode(cert)
	if pemBlock == nil {
		return "", errors.New("invalid pem format cert")
	}

	c, err := x509.ParseCertificate(pemBlock.Bytes)
	if err != nil {
		return "", fmt.Errorf("failed to x509 parse cert,err: %v", err)
	}

	orgId := ""
	if len(c.Issuer.Organization) > 0 {
		orgId = c.Issuer.Organization[0]
	}

	return orgId, nil
}