package consume

import (
	"applet/app/cfg"
	"applet/app/db"
	utils2 "applet/app/utils"
	"applet/app/utils/logx"
	"applet/consume/md"
	"code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
	"code.fnuoos.com/EggPlanet/egg_models.git/src/model"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/enum"
	md2 "code.fnuoos.com/EggPlanet/egg_system_rules.git/rule/egg_energy/md"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/svc/sys_cfg"
	"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/alipay"
	"github.com/go-pay/xlog"
	"github.com/jinzhu/copier"
	"github.com/streadway/amqp"
	"time"
)

func EggFinWithdrawApplyDataConsume(queue md.MqQueue) {
	fmt.Println(">>>>>>>>>>>>EggFinWithdrawApplyDataConsume>>>>>>>>>>>>")
	ch, err := rabbit.Cfg.Pool.GetChannel()
	if err != nil {
		logx.Error(err)
		return
	}
	defer ch.Release()
	//1、将自己绑定到交换机上
	ch.Bind(queue.Name, queue.ExchangeName, queue.RoutKey)
	//2、取出数据进行消费
	ch.Qos(1)
	delivery := ch.Consume(queue.Name, false)
	egg_system_rules.Init(cfg.RedisAddr)
	var alipayStruct *InitAlipayStruct
	client, err := InitAlipay(alipayStruct)
	if err != nil {
		fmt.Println("EggFinWithdrawApplyDataConsume:::::", err.Error())
		utils2.FilePutContents("EggFinWithdrawApplyDataConsume", utils2.SerializeStr(map[string]interface{}{
			"err": err.Error(),
		}))
		return
	}
	var res amqp.Delivery
	var ok bool
	for {
		res, ok = <-delivery
		if ok == true {
			err = handleEggFinWithdrawApplyDataConsume(res.Body, client)
			if err != nil {
				fmt.Println("EggFinWithdrawApplyDataConsume:::::", err.Error())
				utils2.FilePutContents("EggFinWithdrawApplyDataConsume", utils2.SerializeStr(map[string]interface{}{
					"body": res.Body,
					"err":  err.Error(),
				}))

				var data md2.EggFinWithdrawApplyErrorData
				data.ErrorInfo = err.Error()
				// 尝试解析数据结构体
				var msg *md2.EggFinWithdrawApplyData
				err1 := json.Unmarshal(res.Body, &msg)
				if err1 != nil {
					// 无法解析 直接将[]byte推进队列
					data.Ext = res.Body

				} else {
					// 解析成功
					err2 := copier.Copy(&data, &msg)
					if err2 != nil {
						data.Ext = res.Body
					}
				}
				ch.Publish(md2.EggAppExchange, utils2.SerializeStr(data), md2.EggFinWithdrawApplyError)
			}
			//_ = res.Reject(false)
			err = res.Ack(true)
			fmt.Println("err ::: ", err)
		} else {
			panic(errors.New("error getting message"))
		}
	}
}

func handleEggFinWithdrawApplyDataConsume(msgData []byte, client *alipay.Client) error {
	time.Sleep(time.Duration(100) * time.Millisecond) //休眠100毫秒
	// 1.解析mq中queue的数据结构体
	var msg *md2.EggFinWithdrawApplyData
	err := json.Unmarshal(msgData, &msg)
	if err != nil {
		return err
	}

	// 如果不在队列处理阶段或不是自动处理订单,直接返回
	if msg.State != 4 && msg.Type != 2 {
		return nil
	}

	applyDb := implement.NewFinWithdrawApplyDb(db.Db)
	if msg.WithdrawKind == 1 {
		// 2.支付宝提现
		// 2.1 提现
		alipayUserInfoDb := implement.NewAlipayUserInfoDb(db.Db)
		userInfo, err := alipayUserInfoDb.GetAlipayUserInfo(msg.Uid)
		if err != nil {
			return err
		}
		bm := make(gopay.BodyMap)
		bm.Set("out_biz_no", msg.Id).
			Set("trans_amount", msg.Amount).
			Set("biz_scene", "DIRECT_TRANSFER").
			Set("product_code", "TRANS_ACCOUNT_NO_PWD").
			SetBodyMap("payee_info", func(bm gopay.BodyMap) {
				bm.Set("identity", userInfo.OpenId)
				bm.Set("identity_type", "ALIPAY_OPEN_ID")
			})
		_, err = client.FundTransUniTransfer(context.Background(), bm)
		if err != nil {
			return err
		}

		// 2.3 更新 apply 信息
		affected, err := applyDb.UpdateFinWithdrawApply(&model.FinWithdrawApply{State: 2}, "state")
		if err != nil {
			return err
		}
		if affected == 0 {
			return errors.New("更新 apply 状态失败")
		}

	} else if msg.WithdrawKind == 2 {

	}

	return nil
}

type InitAlipayStruct struct {
	IsProd                  bool   `json:"is_prod" label:"是否生产环境"`
	AlipayAppId             string `json:"alipay_app_id" label:"支付宝商家应用appid"`
	AlipayPrivateKey        string `json:"alipay_private_key" label:"支付宝商家应用私钥"`
	AlipayPublicKey         string `json:"alipay_public_key" label:"支付宝商家应用公钥"`
	AlipayPublicContentRSA2 []byte `json:"alipay_public_content_rsa_2" label:"支付宝公钥证书"`
	AlipayRootContent       []byte `json:"alipay_root_content" label:"支付宝根证书"`
	AppPublicContent        []byte `json:"app_public_content" label:"应用公钥证书"`
}

// InitAlipay 初始化支付宝客户端
// appid:应用ID
// privateKey:应用私钥,支持PKCS1和PKCS8
// isProd:是否是正式环境,沙箱环境请选择新版沙箱应用。
func InitAlipay(initData *InitAlipayStruct) (client *alipay.Client, err error) {
	if initData == nil {
		sysCfgDb := sys_cfg.NewSysCfgDb(db.Db)
		sysCfgMap := sysCfgDb.SysCfgFindWithDb(enum.AlipayAppId, enum.AlipayPrivateKey, enum.AlipayPublicKey, enum.AlipayPublicContentRSA2, enum.AlipayRootContent, enum.AppPublicContent)
		initData = &InitAlipayStruct{
			IsProd:                  true,
			AlipayAppId:             sysCfgMap[enum.AlipayAppId],
			AlipayPrivateKey:        sysCfgMap[enum.AlipayPrivateKey],
			AlipayPublicKey:         sysCfgMap[enum.AlipayPublicKey],
			AlipayPublicContentRSA2: []byte(sysCfgMap[enum.AlipayPublicContentRSA2]),
			AlipayRootContent:       []byte(sysCfgMap[enum.AlipayRootContent]),
			AppPublicContent:        []byte(sysCfgMap[enum.AppPublicContent]),
		}
	}
	client, err = alipay.NewClient(initData.AlipayAppId, initData.AlipayPrivateKey, initData.IsProd)
	if err != nil {
		xlog.Error(err)
		return
	}

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

	// 打开Debug开关,输出日志,默认关闭
	client.DebugSwitch = gopay.DebugOn

	client.SetLocation(alipay.LocationShanghai). // 设置时区,不设置或出错均为默认服务器时间
							SetCharset(alipay.UTF8). // 设置字符编码,不设置默认 utf-8
							SetSignType(alipay.RSA2) // 设置签名类型,不设置默认 RSA2

	// SetAppAuthToken("")   //授权token

	//SetReturnUrl("https://www.fmm.ink").            // 设置返回URL
	//	SetNotifyUrl("https://www.fmm.ink").        // 设置异步通知URL

	// 传入 支付宝公钥证书 alipayPublicCert.crt 内容
	client.AutoVerifySign(initData.AlipayPublicContentRSA2)

	// 传入证书内容
	err = client.SetCertSnByContent(initData.AppPublicContent, initData.AlipayRootContent, initData.AlipayPublicContentRSA2)
	if err != nil {
		xlog.Debug("SetCertSn:", err)
		return
	}

	return
}