package wxpay

import (
	"context"
	"errors"
	"fmt"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"goutil/logUtilPlus"
	"log"
	"strconv"
	"time"
)

var (
	mchID                      string = GetWxPayConfig().MchID                      // 商户号
	mchCertificateSerialNumber string = GetWxPayConfig().MchCertificateSerialNumber // 商户证书序列号
	mchAPIv3Key                string = GetWxPayConfig().MchAPIv3Key                // 商户APIv3密钥
	appId                      string = GetWxPayConfig().AppId                      // 应用ID
	Address                    string = "成都市XXXXXXXXXXXXXXXXXXXXXXX"                //公司地址
	wxPayApiUrl                string = GetWxPayConfig().NotifyUrl                  //支付成功回调地址
)

// Prepay 函数用于发起预支付请求。
// 参数:
//
//	outTradeNo: 商户订单号。
//	currency: 订单金额，单位为分。
//	storeId: 商户门店编号。
//	clientIp: 用户的客户端IP。
//	description: 订单描述。
//
// 返回值:
//
//	成功时返回预支付ID和nil错误。
//	失败时返回空字符串和错误对象。
func Prepay(outTradeNo int64, currency int64, storeId string, clientIp string, description string) (string, error) {

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem")
	if err != nil {
		logUtilPlus.ErrorLog("load merchant private key error")
		return "", err
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		logUtilPlus.ErrorLog("new wechat pay client err:%s", err)
		return "", err
	}

	svc := app.AppApiService{Client: client}
	resp, result, err := svc.Prepay(ctx,
		app.PrepayRequest{
			Appid:       core.String(appId),
			Mchid:       core.String(mchID),
			Description: core.String(description),
			OutTradeNo:  core.String(strconv.FormatInt(outTradeNo, 10)),
			TimeExpire:  core.Time(time.Now().Add(time.Hour * 2)),                                 //支付时效时间 2 小时后失效
			Attach:      core.String(""),                                                          //附加数据 这里不需要，有个订单id 可以获取订单详细信息
			NotifyUrl:   core.String(fmt.Sprintf(wxPayApiUrl, strconv.FormatInt(outTradeNo, 10))), //回调地址
			//GoodsTag:      core.String("WXG"),//优惠标记 这里没用
			//LimitPay:      []string{"LimitPay_example"},
			SupportFapiao: core.Bool(false),
			Amount: &app.Amount{
				Currency: core.String("CNY"),
				Total:    core.Int64(currency),
			},
			Detail: &app.Detail{
				//CostPrice: core.Int64(608800),
				GoodsDetail: []app.GoodsDetail{app.GoodsDetail{
					GoodsName:       core.String(storeId), //商品编号
					MerchantGoodsId: core.String(description),
					Quantity:        core.Int64(1),
					UnitPrice:       core.Int64(currency),
					//WechatpayGoodsId: core.String("1001"),
				}},
				//InvoiceId: core.String("wx123"),
			},
			SceneInfo: &app.SceneInfo{
				//DeviceId:      core.String("013467007045764"),
				PayerClientIp: core.String(clientIp),
				StoreInfo: &app.StoreInfo{
					Address: core.String(Address),
					//AreaCode: core.String("440305"),
					//Id:       core.String("0001"),
					//Name:     core.String("腾讯大厦分店"),
				},
			},
			SettleInfo: &app.SettleInfo{
				ProfitSharing: core.Bool(false),
			},
		},
	)

	if err != nil {
		// 处理错误
		logUtilPlus.ErrorLog("call Prepay err:%s", err.Error())
		return "", err
	}

	if result.Response.StatusCode != 200 {
		errStr := fmt.Sprintf("status=%d resp=%s", result.Response.StatusCode, resp)
		logUtilPlus.ErrorLog(errStr)
		return "", errors.New(errStr)
	}

	return *resp.PrepayId, nil
}

// CloseOrder 关闭订单
func CloseOrder(outTradeNo int64) error {

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem")
	if err != nil {
		log.Print("加载商家私钥错误")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("新的 WeChat Pay 客户端 Err:%s", err)
	}

	svc := app.AppApiService{Client: client}
	_, err = svc.CloseOrder(ctx,
		app.CloseOrderRequest{

			//商户系统内部订单号，只能是数字、大小写字母_-*且在同一个商户号下唯
			OutTradeNo: core.String(strconv.FormatInt(outTradeNo, 10)),

			//直连商户的商户号，由微信支付生成并下发。
			Mchid: core.String(mchID),
		},
	)

	if err != nil {
		// 处理错误
		logUtilPlus.ErrorLog("call CloseOrder err:%s", err)
		return err
	}
	return nil
}

// QueryOrderById 根据商户订单号查询订单
func QueryOrderById() {

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
	}

	svc := app.AppApiService{Client: client}
	resp, result, err := svc.QueryOrderById(ctx,
		app.QueryOrderByIdRequest{
			TransactionId: core.String("TransactionId_example"),
			Mchid:         core.String("Mchid_example"),
		},
	)

	if err != nil {
		// 处理错误
		log.Printf("call QueryOrderById err:%s", err)
	} else {
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
	}
}

// QueryOrderByOutTradeNo 根据商户订单号查询订单
func QueryOrderByOutTradeNo(outTradeNo int64) (string, error) {

	//循环查询次数
	var count int = 0

loop:

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
		return "", err
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
		return "", err
	}

	svc := app.AppApiService{Client: client}
	resp, result, err := svc.QueryOrderByOutTradeNo(ctx,
		app.QueryOrderByOutTradeNoRequest{
			OutTradeNo: core.String(strconv.FormatInt(outTradeNo, 10)),
			Mchid:      &mchID,
		},
	)

	if err != nil {
		// 处理错误
		log.Printf("call QueryOrderByOutTradeNo err:%s", err)
		return "", err
	} else {
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)

		//支付成功
		if resp.TradeState == core.String("SUCCESS") {
			return "SUCCESS", nil

		} else if resp.TradeState == core.String("NOTPAY") && count < 3 { //未支付，循环查找订单
			//休息200毫秒
			time.Sleep(200 * time.Millisecond)
			count++
			goto loop
		}

		//支付失败
		return *resp.TradeState, nil
	}
}
