package services

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
	payUtils "github.com/wechatpay-apiv3/wechatpay-go/utils"
	"hongze/hongze_mfyx/models"
	"hongze/hongze_mfyx/models/order"
	"hongze/hongze_mfyx/utils"
	"time"
)

//const (
//	MchPKFileName              = "./utils/cert/apiclient_key.pem"
//	Mchid                      = "1624495680"
//	MchCertificateSerialNumber = "5ED2719CFAE5205763034AD80BF4B8A33533C418"
//	MchAPIv3Key                = "W1tbnzQrzQ7yRRNuQCIHjis8dgdasKVX"
//)
//
//// 微信商户建立连接
//func getWechatClient() (context.Context, *core.Client, error) {
//	// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
//	mchPrivateKey, err := payUtils.LoadPrivateKeyWithPath(MchPKFileName)
//	if err != nil {
//		log.Print("load merchant private key error")
//		return nil, nil, 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 nil, nil, err
//	}
//	return ctx, client, nil
//}

// 生成预支付交易单
func ExampleJsapiApiServicePrepay(orderDetail *order.CygxOrder, unionId string) (JsapiApiResp order.PrepayWithRequestPaymentResponse, err error) {
	//var err error
	defer func() {
		if err != nil {
			fmt.Println(err)
			go utils.SendAlarmMsg(fmt.Sprint("生成预支付交易单失败 ExampleJsapiApiServicePrepay, err:", err.Error(), "unionId:", unionId), 2)
		}
	}()

	userRecord, e := models.GetUserRecordByUnionId(unionId, 10)
	if e != nil && e.Error() != utils.ErrNoRow() {
		err = errors.New("GetUserRecordByUnionId, Err: " + e.Error())
		return
	}
	ctx := context.Background()
	svc := jsapi.JsapiApiService{Client: utils.WechatCertClient}
	// 得到prepay_id,以及调起支付所需的参数和签名
	resp, _, err := svc.PrepayWithRequestPayment(ctx,
		jsapi.PrepayRequest{
			Appid:       core.String(utils.WxAppId),
			Mchid:       core.String(utils.Mchid),
			Description: core.String(orderDetail.SourceTitle),
			OutTradeNo:  core.String(orderDetail.OutTradeNo),
			Attach:      core.String(""),
			NotifyUrl:   core.String(utils.WxPayJsapiNotifyUrl),
			TimeExpire:  core.Time(time.Now().Add(10 * time.Minute)),
			Amount: &jsapi.Amount{
				Total: core.Int64(int64(orderDetail.OrderMoney * 100)), // 分
			},
			Payer: &jsapi.Payer{
				Openid: core.String(userRecord.OpenId),
			},
		},
	)

	if err != nil {
		//log.Printf("PrepayWithRequestPayment err:%s", err)
		return
	}
	JsapiApiResp.PrepayId = *resp.PrepayId
	JsapiApiResp.Appid = *resp.Appid
	JsapiApiResp.TimeStamp = *resp.TimeStamp
	JsapiApiResp.NonceStr = *resp.NonceStr
	JsapiApiResp.Package = *resp.Package
	JsapiApiResp.SignType = *resp.SignType
	JsapiApiResp.PaySign = *resp.PaySign
	return
}

type WechatPayCallback struct {
	MchID          string    `json:"mchid"`
	AppID          string    `json:"appid"`
	OutTradeNo     string    `json:"out_trade_no"`
	TransactionID  string    `json:"transaction_id"`
	TradeType      string    `json:"trade_type"`
	TradeState     string    `json:"trade_state"`
	TradeStateDesc string    `json:"trade_state_desc"`
	BankType       string    `json:"bank_type"`
	Attach         string    `json:"attach"`
	SuccessTime    time.Time `json:"success_time"`
	Payer          struct {
		OpenID string `json:"openid"`
	} `json:"payer"`
	Amount struct {
		Total         int    `json:"total"`
		PayerTotal    int    `json:"payer_total"`
		Currency      string `json:"currency"`
		PayerCurrency string `json:"payer_currency"`
	} `json:"amount"`
}

// 微信支付回调内容解密
func WxDecodeNotify(body []byte) (wechatPayCallback *WechatPayCallback) {
	var err error
	defer func() {
		if err != nil {
			fmt.Println(err)
			go utils.SendAlarmMsg(fmt.Sprint("微信支付回调内容解密失败 WxDecodeNotify, err:", err.Error()), 2)
		}
	}()

	var prepaymap map[string]interface{}
	_ = json.Unmarshal(body, &prepaymap)

	var prepaymap2 = prepaymap["resource"].(map[string]interface{})
	nonce := prepaymap2["nonce"].(string)
	associatedData := prepaymap2["associated_data"].(string)
	ciphertext := prepaymap2["ciphertext"].(string)

	tx, e := payUtils.DecryptAES256GCM(utils.MchAPIv3Key, associatedData, nonce, ciphertext)
	if e != nil {
		err = errors.New("DecryptAES256GCM, Err: " + e.Error())
		return
	}
	var datamap *WechatPayCallback
	_ = json.Unmarshal([]byte(tx), &datamap)
	wechatPayCallback = datamap
	return
}

// Transaction
type Transaction struct {
	Amount          TransactionAmount `json:"amount,omitempty"`
	Appid           string            `json:"appid,omitempty"`
	Attach          string            `json:"attach,omitempty"`
	BankType        string            `json:"bank_type,omitempty"`
	Mchid           string            `json:"mchid,omitempty"`
	OutTradeNo      string            `json:"out_trade_no,omitempty"`
	Payer           TransactionPayer  `json:"payer,omitempty"`
	PromotionDetail []PromotionDetail `json:"promotion_detail,omitempty"`
	SuccessTime     time.Time         `json:"success_time,omitempty"`
	TradeState      string            `json:"trade_state,omitempty"`
	TradeStateDesc  string            `json:"trade_state_desc,omitempty"`
	TradeType       string            `json:"trade_type,omitempty"`
	TransactionId   string            `json:"transaction_id,omitempty"`
}

// TransactionAmount
type TransactionAmount struct {
	Currency      string `json:"currency,omitempty"`
	PayerCurrency string `json:"payer_currency,omitempty"`
	PayerTotal    int64  `json:"payer_total,omitempty"`
	Total         int64  `json:"total,omitempty"`
}

// PromotionDetail
type PromotionDetail struct {
	// 券ID
	CouponId *string `json:"coupon_id,omitempty"`
	// 优惠名称
	Name *string `json:"name,omitempty"`
	// GLOBAL:全场代金券;SINGLE:单品优惠
	Scope *string `json:"scope,omitempty"`
	// CASH:充值;NOCASH:预充值。
	Type *string `json:"type,omitempty"`
	// 优惠券面额
	Amount *int64 `json:"amount,omitempty"`
	// 活动ID,批次ID
	StockId *string `json:"stock_id,omitempty"`
	// 单位为分
	WechatpayContribute *int64 `json:"wechatpay_contribute,omitempty"`
	// 单位为分
	MerchantContribute *int64 `json:"merchant_contribute,omitempty"`
	// 单位为分
	OtherContribute *int64 `json:"other_contribute,omitempty"`
	// CNY:人民币,境内商户号仅支持人民币。
	Currency    *string                `json:"currency,omitempty"`
	GoodsDetail []PromotionGoodsDetail `json:"goods_detail,omitempty"`
}

// PromotionGoodsDetail
type PromotionGoodsDetail struct {
	// 商品编码
	GoodsId *string `json:"goods_id"`
	// 商品数量
	Quantity *int64 `json:"quantity"`
	// 商品价格
	UnitPrice *int64 `json:"unit_price"`
	// 商品优惠金额
	DiscountAmount *int64 `json:"discount_amount"`
	// 商品备注
	GoodsRemark *string `json:"goods_remark,omitempty"`
}

// TransactionPayer
type TransactionPayer struct {
	Openid string `json:"openid,omitempty"`
}

// 根据订单号查询订单状态
func GetQueryOrderByOutTradeNo(outTradeNo string) (tradeState string, statusCode int, itemResp *Transaction) {
	var err error
	defer func() {
		if err != nil {
			fmt.Println("err", err)
			go utils.SendAlarmMsg(fmt.Sprint("根据订单号查询订单状态 失败 GetQueryOrderByOutTradeNo, err:", err.Error(), "outTradeNo", outTradeNo), 2)
		}
	}()
	ctx := context.Background()
	svc := jsapi.JsapiApiService{Client: utils.WechatCertClient}
	resp, result, err := svc.QueryOrderByOutTradeNo(ctx,
		jsapi.QueryOrderByOutTradeNoRequest{
			OutTradeNo: core.String(outTradeNo),
			Mchid:      core.String(utils.Mchid),
		},
	)
	statusCode = result.Response.StatusCode

	//订单状态码不存在直接返回
	if statusCode == 404 {
		err = nil
		return
	}
	tradeState = *resp.TradeState
	data, err := json.Marshal(resp)
	if err != nil {
		return
	}
	jsonstr := string(data)
	//item := new(Transaction)
	if err = json.Unmarshal([]byte(jsonstr), &itemResp); err != nil {
		return
	}
	//utils.FileLog.Info(jsonstr)
	////itemResp = item
	//fmt.Println(itemResp)
	//fmt.Println(tradeState)
	//fmt.Println(itemResp.TransactionId)
	return
}