package paymentService

import (
	"PaymentCenter/app/third/paymentService/payCommon"
	"context"
	"errors"
	"fmt"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/wechat/v3"
	"sync"
	"time"
)

var (
	wxClient  *wechat.ClientV3
	clientErr error
	once      sync.Once
)

// InitClient 使用提供的支付请求参数初始化微信客户端
func InitClient(wxConfig WxPay) {
	once.Do(func() {
		// NewClientV3 初始化微信客户端 v3
		// mchid:商户ID 或者服务商模式的 sp_mchid
		// serialNo:商户证书的证书序列号
		// apiV3Key:apiV3Key,商户平台获取
		// privateKey:私钥 apiclient_key.pem 读取后的内容
		wxClient, clientErr = wechat.NewClientV3(
			wxConfig.MchId,
			wxConfig.SerialNo,
			wxConfig.ApiV3Key,
			wxConfig.PrivateKey,
		)
	})
	// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
	clientErr = wxClient.AutoVerifySign()

	// 自定义配置http请求接收返回结果body大小,默认 10MB
	wxClient.SetBodySize(10) // 没有特殊需求,可忽略此配置

	// 打开Debug开关,输出日志,默认是关闭的
	wxClient.DebugSwitch = gopay.DebugOn
}

// GetClient 获取已经初始化的微信客户端
func GetClient() (*wechat.ClientV3, error) {
	if wxClient == nil {
		return nil, errors.New("client not initialized")
	}
	if clientErr != nil {
		return nil, clientErr
	}
	return wxClient, nil
}

// WxH5PayInfo 微信H5支付
func WxH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
	// 初始化微信客户端
	InitClient(payOrderRequest.Wx)

	// 获取微信客户端
	wxClient, err := GetClient()
	if err != nil {
		fmt.Println("Failed to get client:", err)
		return "", err
	}
	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
	// 初始化 BodyMap
	bm := make(gopay.BodyMap)
	bm.Set("appid", payOrderRequest.Wx.AppId).
		Set("mchid", payOrderRequest.Wx.MchId).
		Set("description", payOrderRequest.Description).
		Set("out_trade_no", payOrderRequest.OrderId).
		Set("time_expire", expire).
		Set("notify_url", payCommon.WX_NOTIFY_URL).
		SetBodyMap("amount", func(bm gopay.BodyMap) {
			bm.Set("total", payOrderRequest.Amount).
				Set("currency", "CNY")
		}).
		SetBodyMap("scene_info", func(bm gopay.BodyMap) {
			bm.Set("payer_client_ip", payOrderRequest.PayerClientIp).
				SetBodyMap("h5_info", func(bm gopay.BodyMap) {
					bm.Set("type", "common")
				})
		})

	wxRsp, err := wxClient.V3TransactionH5(c, bm)
	if err != nil {
		return "", err
	}
	if wxRsp.Code != wechat.Success || wxRsp.Response.H5Url == "" {
		return "", errors.New(fmt.Sprintf("发起支付失败,失败状态码:%d, 失败原因:%s", wxRsp.Code, wxRsp.Error))
	}
	return wxRsp.Response.H5Url, nil
}

//func WxPayCallBack(notifyReq *wechat.V3NotifyReq) error {
//	//	获取附加数据中的信息
//	appId := notifyReq.Resource.AssociatedData
//
//	payOrderRequest := PayOrderRequest{}
//	// 初始化微信客户端
//	InitClient(payOrderRequest)
//
//	// 获取微信客户端
//	wxClient, err := GetClient()
//	if err != nil {
//		fmt.Println("Failed to get client:", err)
//		return err
//	}
//
//	// 获取微信平台证书
//	certMap := wxClient.WxPublicKeyMap()
//	// 验证异步通知的签名
//	err = notifyReq.VerifySignByPKMap(certMap)
//	if err != nil {
//		return err
//	}
//	objPtr := ""
//	// 通用通知解密(推荐此方法)
//	result := notifyReq.DecryptCipherTextToStruct(apiV3Key, objPtr)
//}

// WxOrderQuery 查询微信订单
func WxOrderQuery(ctx context.Context, wxConfig WxPay, orderNo string) (PayOrderQueryInfo, error) {
	// 初始化微信客户端
	InitClient(wxConfig)

	// 获取微信客户端
	wxClient, err := GetClient()
	if err != nil {
		fmt.Println("Failed to get client:", err)
		return PayOrderQueryInfo{}, err
	}

	wxRsp, err := wxClient.V3TransactionQueryOrder(ctx, payCommon.ORDER_NO_TYPE_ORDER_NO, orderNo)
	if err != nil {
		return PayOrderQueryInfo{}, err
	}
	if wxRsp.Code != wechat.Success {
		return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("查询订单接口错误,错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
	}

	//	映射交易状态
	tradeState := ""
	switch wxRsp.Response.TradeState {
	case "SUCCESS":
		tradeState = "SUCCESS"
	case "REFUND":
		tradeState = "REFUND"
	case "NOTPAY":
		tradeState = "NOTPAY"
	case "CLOSED":
		tradeState = "CLOSED"
	}
	amountTotal := wxRsp.Response.Amount.Total
	payerTotal := wxRsp.Response.Amount.PayerTotal

	return PayOrderQueryInfo{
		AppId:          wxRsp.Response.Appid,
		OutTradeNo:     wxRsp.Response.OutTradeNo,
		TransactionId:  wxRsp.Response.TransactionId,
		TradeState:     tradeState,
		TradeStateDesc: wxRsp.Response.TradeStateDesc,
		SuccessTime:    wxRsp.Response.SuccessTime,
		AmountTotal:    int64(amountTotal),
		PayerTotal:     int64(payerTotal),
	}, nil
}