package payment

import (
	"encoding/json"
	"errors"
	"fengkuangGameServerJob/pkg/feishu"
	"fengkuangGameServerJob/pkg/setting"
	"fengkuangGameServerJob/pkg/util"
	"fengkuangGameServerJob/service"
	"fmt"
	"github.com/beego/beego/v2/adapter/httplib"
	"github.com/gin-gonic/gin"
	"log"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type SYPay struct {
	secret  string //每个游戏包的密钥不一样,需要根据不同的游戏包获取
	orderId string
}

func NewSYPay() *SYPay {
	return &SYPay{}
}

// Callback 请求回调
func (s *SYPay) Callback(c *gin.Context) (orderSn string, err error) {
	//1.请求数据解析
	var callback SyCallBack
	if c.ShouldBind(&callback) != nil || callback.Validate() != nil {
		return "", errors.New("params error")
	}
	//1.1 通过订单号找到具体包,找到对应的密钥
	orderService := service.NewOrderService()
	secret := orderService.GetSecret(callback.OrderId)
	if secret == "" {
		//订单信息没有找到转发到0.1支付回调上去
		RelayToD1(callback, setting.Settings.Server.RunMode)
		return service.Relay, nil
	}
	s.secret = secret
	//2.验证签名
	callbackMap := util.Struct2Map(callback)
	tmpSign := util.GenSignMD5(callbackMap, s.secret)
	if tmpSign != callback.Sign {
		return "", errors.New("sign error")
	}
	//3. 二次校验订单是否支付
	s.orderId = callback.OrderId
	err = s.OrderInfo()
	if err != nil {
		return "", errors.New("order error")
	}
	//4. 返回单号等待处理
	return s.orderId, err
}

// OrderInfo 订单详情
func (s *SYPay) OrderInfo() error {
	//请求上游查询接口，判断订单是否真的成功
	tmpToSignStr := fmt.Sprintf("channel=%s&orderid=%s", s.secret, s.orderId)
	sign := util.EncodeMD5(tmpToSignStr)
	req := httplib.Post("http://docater1.cn/index.php?g=Wap&m=MiniGame&a=getPayInfo")
	req.Param("channel", s.secret)
	req.Param("orderid", s.orderId)
	req.Param("sign", sign)
	byteRes, err := req.Bytes()
	if err != nil {
		return errors.New("http request err")
	}
	var syPayInfo SyPayInfo
	err = json.Unmarshal(byteRes, &syPayInfo)
	if err != nil {
		return errors.New("http result err")
	}
	if strings.ToUpper(syPayInfo.Data.State) != "SUCCESS" {
		return errors.New("un pay")
	}
	//订单金额校验(金额可能是浮点数)
	price, _ := strconv.ParseFloat(syPayInfo.Data.Price, 64)
	if price <= 0 {
		return errors.New("price err")
	}
	orderService := service.NewOrderService()
	orderInfo := orderService.GetOrderInfo(s.orderId)
	if orderInfo.OrderPrice != int(price*100) {
		openid := syPayInfo.Data.OpenID
		content := fmt.Sprintf("[用户订单异常]\nplayer_id：%d\nopenid： %s\n戳爆三国订单id：%s\n戳爆三国订单支付金额：%d分\n发行侧回调支付金额：%v分\n", orderInfo.PlayerId, openid, orderInfo.OrderSn, orderInfo.OrderPrice, price*100)
		notify := feishu.NewFeiShu(feishu.OrderErr)
		notify.BaseNotify(content)
		//修改订单号为金额不匹配
		s.orderId = service.PriceNotMatchOrderSn
	}
	return nil
}

// ReplyContent 校验成功后返回给上游的内容
func (s *SYPay) ReplyContent() string {
	return strings.ToLower("SUCCESS")
}

// SyCallBack 盛也支付回调的参数
type SyCallBack struct {
	OrderId string `form:"orderid" json:"orderid" `
	OpenId  string `form:"openid" json:"openid"`
	//Price   int    `form:"price" json:"price" `
	Price  string `form:"price" json:"price" `
	ItemId int    `form:"item_id" json:"item_id"`
	Other  string `form:"other" json:"other"`
	Sign   string `form:"sign" json:"sign" `
}

// Validate 校验参数
func (s *SyCallBack) Validate() error {
	s.OrderId = strings.TrimSpace(s.OrderId)
	s.OpenId = strings.TrimSpace(s.OpenId)
	s.Other = strings.TrimSpace(s.Other)
	s.Sign = strings.TrimSpace(s.Sign)
	tmpPrice, _ := strconv.ParseFloat(s.Price, 64)
	if isOrderSn(s.OrderId) == false || s.Sign == "" || tmpPrice <= 0 {
		return errors.New("parameter invalid")
	}
	return nil
}

// SyPayInfo PayInfo 查询订单接口返回
type SyPayInfo struct {
	Data struct {
		ExtendParam1 string `json:"extend_param1"`
		ExtendParam2 string `json:"extend_param2"`
		ItemID       string `json:"item_id"`
		OpenID       string `json:"openId"`
		OrderId      string `json:"orderid"`
		Other        string `json:"other"`
		Price        string `json:"price"`
		State        string `json:"state"`
	} `json:"data"`
	Info   string `json:"info"`
	Status int64  `json:"status"`
}

// 校验sy的单号格式是否正确
func isOrderSn(orderSn string) bool {
	if m, _ := regexp.MatchString(`^\w+$`, orderSn); !m {
		return false
	}
	return true
}

// RelayToD1 转发消息到0.1折支付回调
func RelayToD1(callback SyCallBack, mod string) {
	//判断是正式环境还是开发环境
	domain := ""
	if mod == "release" {
		domain = "https://server.game.wanhuir.com/discount/pay/callback/sy"
	} else {
		domain = "https://dev-server.game.wanhuir.com/discount/pay/callback/sy"
	}
	for i := 0; i < 3; i++ {
		req := httplib.Post(domain)
		req.Header("Content-Type", "application/x-www-form-urlencoded").SetTimeout(10*time.Second, 3*time.Second)
		req.Param("item_id", fmt.Sprintf("%d", callback.ItemId))
		req.Param("openid", callback.OpenId)
		req.Param("orderid", callback.OrderId)
		req.Param("other", callback.Other)
		req.Param("price", callback.Price)
		req.Param("sign", callback.Sign)
		ret, err := req.String()
		log.Println(fmt.Sprintf("orderId=%s, ret=%s, mod=%s", callback.OrderId, ret, mod))
		if err == nil {
			break
		}
		time.Sleep(time.Second)
	}
}
