package platformPay

import (
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"leafstalk/log"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"
)

var (
	dyAccessToken        string
	dyAccessTokenExpires int64
	DyAppId              = "tt657f13c2fa40ef9802"

	DYBalanceUri = "/api/apps/game/wallet/get_balance"
	DYpayUri     = "/api/apps/game/wallet/game_pay"
	DyPaySecret  = "8a25288267fa81f75581b5018378cb0e"
)

// 从中台获取抖音支付TOKEN

// 抖音查询余额签名函数
func DyMakeQueryBalanceSig(md map[string]interface{}, uri string) string {

	var str string
	var ms []string
	for k, v := range md {
		switch v := v.(type) {
		case string:
			str = k + "=" + v
			ms = append(ms, str)
		case int:
			str = k + "=" + strconv.FormatInt(int64(v), 10)
			ms = append(ms, str)
		case int64:
			str = k + "=" + strconv.FormatInt(v, 10)
			ms = append(ms, str)
		}
	}
	sort.Strings(ms)

	str = "org_loc=" + uri
	ms = append(ms, str)
	str = "method=POST"
	ms = append(ms, str)

	var nstr string = strings.Join(ms, "&")
	r := hmacSha256(nstr, DyPaySecret)
	return r
}

// 查询余额接口

func DyQueryBalance(openid string) (*ResponseGetBalance, error) {
	req := NewHttpRequest()

	requestData := make(map[string]interface{})
	requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
	requestData["appid"] = DyAppId //"wx831355257c862ac2"
	// requestData["offer_id"] = offerId //"1450030892"
	requestData["ts"] = time.Now().Unix()
	requestData["zone_id"] = "1"
	requestData["pf"] = "android"
	requestData["access_token"] = dyAccessToken                              //dyAccessToken
	requestData["mp_sig"] = DyMakeQueryBalanceSig(requestData, DYBalanceUri) //(requestData, getBalanceUri)

	// https://developer.toutiao.com/api/apps/game/wallet/get_balance
	url := "https://developer.toutiao.com" + DYBalanceUri
	resp, err := req.JSON(requestData).Post(url)
	if err != nil {
		//log.Warnln(err)
		return nil, err
	}
	defer func() {
		if resp.GetBody() != nil {
			resp.GetBody().Close()
		}
	}()
	if resp.GetStatusCode() != http.StatusOK {
		return nil, errors.New(fmt.Sprintf("请求余额失败:%v", resp.GetStatusCode()))
	}
	res := new(ResponseGetBalance)
	err = resp.UnmarshalBody(res)
	if err != nil {
		return nil, err
	}
	if res.ErrCode != 0 {
		return nil, errors.New(res.ErrMsg)
	}
	return res, nil
}

func DyQueryBalanceAndCheck(openid string) (*ResponseGetBalance, error) {
	// token不存在或过期则去请求
	if len(dyAccessToken) == 0 || time.Now().Unix() > dyAccessTokenExpires-60 {
		token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires)
		if err == nil {
			dyAccessToken = token
			dyAccessTokenExpires = expired
		}
	}
	rgb, err := DyQueryBalance(openid)
	if err != nil {
		return rgb, err
	}

	// 繁忙再请求
	if rgb.ErrCode == -1 {
		rgb, err = DyQueryBalance(openid)
	}

	// token失效再请求
	if rgb.ErrCode == 90017 || rgb.ErrCode == 90018 { // rgb.ErrCode == 40001 || rgb.ErrCode == 41001 ||
		token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires)
		if err == nil {
			dyAccessToken = token
			dyAccessTokenExpires = expired
			return DyQueryBalance(openid)
		}
	}
	return rgb, err
}

// 扣除余额接口
func DyPay(openid string, billNo string, amt int) (*ResponsePay, error) {
	req := NewHttpRequest()

	requestData := make(map[string]interface{})
	requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
	requestData["appid"] = DyAppId //"wx831355257c862ac2"
	// requestData["offer_id"] = offerId //"1450030892"
	requestData["ts"] = time.Now().Unix()
	requestData["zone_id"] = "1"
	requestData["pf"] = "android"

	requestData["amt"] = amt
	requestData["bill_no"] = billNo
	//requestData["pay_item"] = "钻石"

	requestData["access_token"] = dyAccessToken
	requestData["mp_sig"] = DyMakeQueryBalanceSig(requestData, DYpayUri)

	// https://developer.toutiao.com/api/apps/game/wallet/game_pay
	url := "https://developer.toutiao.com" + DYpayUri
	logrus.Infof("DyPay params: %+v", requestData)
	resp, err := req.JSON(requestData).Post(url)
	if err != nil {
		//log.Warnln(err)
		return nil, err
	}
	defer func() {
		if resp.GetBody() != nil {
			resp.GetBody().Close()
		}
	}()

	if resp.GetStatusCode() == 200 {
		res := new(ResponsePay)
		resp.UnmarshalBody(res)
		//log.Warnf("%#v", res)
		return res, nil
	}
	return nil, nil

}

func DyPayAndCheck(openid string, billNo string, amt int) (*ResponsePay, error) {
	var rp *ResponsePay
	var err error
	for i := 0; i < 3; i++ {
		rp, err = DyPay(openid, billNo, amt)
		if err != nil {
			log.Warnf("DyPayAndCheck error: %v", err)
			time.Sleep(time.Millisecond * 10)
			continue
		}
		if rp.ErrCode == 0 {
			return rp, err
		}
		if rp.ErrCode == -1 {
			continue
		}
		if rp.ErrCode == 90017 || rp.ErrCode == 90018 {
			token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires)
			if err != nil {
				return rp, err
			}

			dyAccessToken = token
			dyAccessTokenExpires = expired
			continue
		}
		if rp.ErrCode < 0 {
			time.Sleep(time.Millisecond * 10)
			continue
		}
		return rp, err
	}
	return rp, err
}

// // 有效期2小时，定时刷新，提前刷新，会导致前一个token有效期变为5分钟；
// func QueryDouYinAccessToken() error {

// 	req := NewHttpRequest()

// 	requestData := make(map[string]string)
// 	requestData["grant_type"] = "client_credential"
// 	requestData["appid"] = service.appId
// 	requestData["secret"] = service.appSecret

// 	resp, err := req.Query(requestData).Get(config.AppConfig.WxRefreshTokenUrl)
// 	logrus.Info("query params:", requestData)
// 	if err != nil {
// 		//log.Warnln(err)
// 		return err
// 	}
// 	defer func() {
// 		if resp.GetBody() != nil {
// 			resp.GetBody().Close()
// 		}
// 	}()

// 	if resp.GetStatusCode() == 200 {
// 		rt := new(ResponseAccessToken)
// 		err := resp.UnmarshalBody(rt)
// 		if err != nil {
// 			logrus.Warnln("parse AccessToken err:", err.Error())
// 			return err
// 		}

// 		if rt.ErrCode == 0 {

// 			AccessToken := rt.AccessToken
// 			//失效时间缩短一分钟
// 			AccessTokenExpiredAt := time.Now().Add(time.Second * time.Duration(rt.ExpiresIn-60)).Unix()

// 			service.UpdateAccessToken(AccessToken, AccessTokenExpiredAt)
// 			atomic.StoreInt32(&service.ExpiredReportCount, 0)
// 		}
// 		logrus.Info("query resp:", rt)
// 	} else {
// 		logrus.Info("query resp code:", resp.GetStatusCode())
// 		body, err := resp.GetBodyAsString()
// 		logrus.Info("query resp body:", body)
// 		logrus.Info("query resp err:", err.Error())
// 	}

// 	return nil, nil
// }
