package cloudauth

import (
	"encoding/json"
	"fmt"

	cloudauth "github.com/alibabacloud-go/cloudauth-20190307/v4/client"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	util "github.com/alibabacloud-go/tea-utils/v2/service"

	"github.com/alibabacloud-go/tea/tea"
	"github.com/aliyun/credentials-go/credentials"
	"github.com/zeromicro/go-zero/core/logx"
)

type CloudAuthClient struct {
	Client *cloudauth.Client
	Config *CloudAuthConfig
}

type CloudAuthConfig struct {
	AccessKeyId     string
	AccessKeySecret string
	Endpoint        string
	SceneId         int64
	ReturnUrl       string
}
type InitFaceVerifyResp struct {
	CertifyId  string
	CertifyUrl string
}
type DescribeFaceVerifyResp struct {
	Passed bool
}

// InitFaceVerifyRequest 封装初始化人脸认证所需参数
type InitFaceVerifyParam struct {
	OuterOrderNo string
	CertName     string
	CertNo       string
	MetaInfo     string
}

// NewCloudAuthClient 创建阿里云人脸认证客户端
func NewCloudAuthClient(cloudAuthconfig CloudAuthConfig) (*CloudAuthClient, error) {
	// 使用AK 初始化Credentials Client。
	credentialsConfig := new(credentials.Config).
		// 凭证类型。
		SetType("access_key").
		// 设置为AccessKey ID值。
		SetAccessKeyId(cloudAuthconfig.AccessKeyId).
		// 设置为AccessKey Secret值。
		SetAccessKeySecret(cloudAuthconfig.AccessKeySecret)
	credentialClient, _err := credentials.NewCredential(credentialsConfig)
	if _err != nil {
		panic(_err)
	}

	ecsConfig := &openapi.Config{}
	// 配置云产品服务接入地址（endpoint）。
	ecsConfig.Endpoint = tea.String(cloudAuthconfig.Endpoint)
	// 使用Credentials配置凭证。
	ecsConfig.Credential = credentialClient

	// 创建客户端
	client, err := cloudauth.NewClient(ecsConfig)
	if err != nil {
		panic(fmt.Sprintf("创建阿里云人脸认证客户端失败: %v", err))
	}

	return &CloudAuthClient{
		Client: client,
		Config: &CloudAuthConfig{
			AccessKeyId:     cloudAuthconfig.AccessKeyId,
			AccessKeySecret: cloudAuthconfig.AccessKeySecret,
			Endpoint:        cloudAuthconfig.Endpoint,
			SceneId:         cloudAuthconfig.SceneId,
			ReturnUrl:       cloudAuthconfig.ReturnUrl,
		},
	}, nil
}

// InitFaceVerify 初始化人脸认证
func (c *CloudAuthClient) InitFaceVerify(param InitFaceVerifyParam) (*InitFaceVerifyResp, error) {
	request := &cloudauth.InitFaceVerifyRequest{
		SceneId:      tea.Int64(c.Config.SceneId),
		OuterOrderNo: tea.String(param.OuterOrderNo),
		ProductCode:  tea.String("ID_PRO"),
		Model:        tea.String("LIVENESS"),
		CertType:     tea.String("IDENTITY_CARD"),
		CertName:     tea.String(param.CertName),
		CertNo:       tea.String(param.CertNo),
		MetaInfo:     tea.String(param.MetaInfo),
		ReturnUrl:    tea.String(c.Config.ReturnUrl),
	}

	runtime := &util.RuntimeOptions{
		ReadTimeout:    tea.Int(10000),
		ConnectTimeout: tea.Int(5000),
	}

	response, err := c.Client.InitFaceVerifyWithOptions(request, runtime)
	if err != nil {
		if sdkErr, ok := err.(*tea.SDKError); ok {
			logx.Errorf("认证初始化失败: %s, 建议: %s",
				tea.StringValue(sdkErr.Message),
				getRecommendFromError(sdkErr))
			return nil, fmt.Errorf("认证初始化失败: %s", tea.StringValue(sdkErr.Message))
		}
		logx.Errorf("认证初始化失败: %v", err)
		return nil, fmt.Errorf("认证初始化失败: %v", err)
	}

	if tea.StringValue(response.Body.Code) != "200" {
		logx.Errorf("认证初始化失败: %s", tea.StringValue(response.Body.Message))
		return nil, fmt.Errorf("认证初始化失败: %s", tea.StringValue(response.Body.Message))
	}

	return &InitFaceVerifyResp{
		CertifyId:  tea.StringValue(response.Body.ResultObject.CertifyId),
		CertifyUrl: tea.StringValue(response.Body.ResultObject.CertifyUrl),
	}, nil
}

// DescribeFaceVerify 获取认证结果
func (c *CloudAuthClient) DescribeFaceVerify(certifyId string) (*DescribeFaceVerifyResp, error) {
	request := &cloudauth.DescribeFaceVerifyRequest{
		SceneId:   tea.Int64(c.Config.SceneId),
		CertifyId: tea.String(certifyId),
	}

	runtime := &util.RuntimeOptions{
		ReadTimeout:    tea.Int(10000),
		ConnectTimeout: tea.Int(5000),
	}
	response, err := c.Client.DescribeFaceVerifyWithOptions(request, runtime)
	if err != nil {
		logx.Errorf("获取认证结果失败: %v", err)
		return nil, fmt.Errorf("获取认证结果失败: %v", err)
	}

	if tea.StringValue(response.Body.Code) != "200" {
		logx.Errorf("获取认证结果失败: %s", tea.StringValue(response.Body.Message))
		return nil, fmt.Errorf("获取认证结果失败: %s", tea.StringValue(response.Body.Message))
	}
	var passed bool
	var passedStr = tea.StringValue(response.Body.ResultObject.Passed)

	switch passedStr {
	case "T":
		passed = true
	case "F":
		passed = false
	default:
		passed = false
	}
	return &DescribeFaceVerifyResp{
		Passed: passed,
	}, nil
}

// 从SDK错误中获取推荐信息
func getRecommendFromError(err *tea.SDKError) string {
	if err == nil || err.Data == nil {
		return ""
	}

	var data map[string]interface{}
	if err := json.Unmarshal([]byte(tea.StringValue(err.Data)), &data); err != nil {
		return ""
	}

	if recommend, ok := data["Recommend"].(string); ok {
		return recommend
	}

	return ""
}
