package platformPay

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"github.com/sirupsen/logrus"
	"leafstalk/log"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

var (
	//appId     string
	//appSecret string
	//
	//offerId     string
	//midasSecret string
	//
	wxAccessToken        string
	wxAccessTokenExpires = time.Now().Unix()

	getBalanceUri = "/cgi-bin/midas/getbalance"
	payUri        = "/cgi-bin/midas/pay"
	cancelPayUri  = "/cgi-bin/midas/cancelpay"
	presentUri    = "/cgi-bin/midas/present"
)

func CreateOutTradeNo(id int64) string {
	n := time.Now().Unix()
	return fmt.Sprintf("%v%vS%vU%d", time.Now().Format("20060102150405"), 999, id, n%65536)
}

func hmacSha256(msg string, secret string) string {
	k := []byte(secret)
	h := hmac.New(sha256.New, k)
	h.Write([]byte(msg))
	sha := hex.EncodeToString(h.Sum(nil))
	return sha
	//base64.StdEncoding.EncodeToString([]byte(sha))
}

func MakeGetBalanceSig(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)
	str = "secret=" + os.Getenv("WXPAY_MIDASSECRET")
	ms = append(ms, str)

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

//SIG
//requestData := make(map[string]interface{})
// requestData["openid"] = "odkx20ENSNa2w5y3g_qOkOvBNM1g"
// requestData["appid"] = "wx1234567"
// requestData["offer_id"] = "12345678"
// requestData["ts"] = int64(1507530737)
// requestData["zone_id"] = "1"
// requestData["pf"] = "android"
// midasSecret = "zNLgAGgqsEWJOg1nFVaO5r7fAlIQxr1u"
//result: "1ad64e8dcb2ec1dc486b7fdf01f4a15159fc623dc3422470e51cf6870734726b"

func GetAccessToken(platform int) string {
	if platform == int(WxPlat) {
		return wxAccessToken
	} else {
		return dyAccessToken
	}
}

type ResponseGetBalance struct {
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
	Balance    int    `json:"balance"`     //游戏币个数（包含赠送）
	GenBalance int    `json:"gen_balance"` //赠送游戏币数量（赠送游戏币数量）
	FirstSave  int    `json:"first_save"`  //是否满足历史首次充值
	SaveAmt    int    `json:"save_amt"`    //累计充值金额的游戏币数量
	SaveSum    int    `json:"save_sum"`    //历史总游戏币金额
	CostSum    int    `json:"cost_sum"`    //历史总消费游戏币金额
	PresentSum int    `json:"present_sum"` //历史累计收到赠送金额
}

// 查询余额
func WxQueryBalance(openid string) (*ResponseGetBalance, error) {
	req := NewHttpRequest()

	requestData := make(map[string]interface{})
	requestData["openid"] = openid                       //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
	requestData["appid"] = os.Getenv("WXPAY_APPID")      //"wx831355257c862ac2"
	requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892"
	requestData["ts"] = time.Now().Unix()
	requestData["zone_id"] = "1"
	requestData["pf"] = "android"
	requestData["sig"] = MakeGetBalanceSig(requestData, getBalanceUri)
	requestData["access_token "] = wxAccessToken

	url := "https://api.weixin.qq.com" + getBalanceUri + "?access_token=" + wxAccessToken
	logrus.Warnf("url:%+v， requestData%+v", url, 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(ResponseGetBalance)
		err := resp.UnmarshalBody(res)
		if err != nil {
			return nil, err
		}
		//log.Warnf("%#v", res)
		return res, nil
	}

	logrus.Warnf("resp.GetStatusCode():%v", resp.GetStatusCode())

	return nil, nil
}

func WxQueryBalanceAndCheck(openid string) (*ResponseGetBalance, error) {
	rgb, err := WxQueryBalance(openid)
	if err != nil {
		return rgb, err
	}
	if rgb.ErrCode == 40001 || rgb.ErrCode == 41001 || rgb.ErrCode == 42001 {
		token, expired, err := QueryAccessToken(int(WxPlat), wxAccessTokenExpires)
		if err == nil {
			wxAccessToken = token
			wxAccessTokenExpires = expired
			return WxQueryBalance(openid)
		}
	}
	return rgb, err
}

type ResponsePay struct {
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
	BillNo     string `json:"bill_no"`
	Balance    int    `json:"balance"`      //预扣后的余额
	UsedGenAmt int    `json:"used_gen_amt"` //本次扣的赠送币的金额
}

// 支付
func WxPay(openid string, billNo string, amt int) (*ResponsePay, error) {
	req := NewHttpRequest()

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

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

	requestData["sig"] = MakeGetBalanceSig(requestData, payUri)
	requestData["access_token "] = wxAccessToken

	url := "https://api.weixin.qq.com" + payUri + "?access_token=" + wxAccessToken
	//url := "https://api.weixin.qq.com/cgi-bin/midas/sandbox/pay?access_token=" + accessToken
	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)
		err := resp.UnmarshalBody(res)
		if err != nil {
			return nil, err
		}
		//log.Warnf("%#v", res)
		return res, nil
	}
	return nil, nil
}

func WxPayAndCheck(openid string, billNo string, amt int) (*ResponsePay, error) {
	var rp *ResponsePay
	var err error
	for i := 0; i < 3; i++ {
		rp, err = WxPay(openid, billNo, amt)
		if err != nil {
			log.Warnf("PayAndCheck error: %v", err)
			time.Sleep(time.Millisecond * 10)
			continue
		}
		if rp.ErrCode == 0 {
			return rp, err
		}

		if rp.ErrCode == 40001 || rp.ErrCode == 41001 || rp.ErrCode == 42001 {

			token, expired, err := QueryAccessToken(int(WxPlat), wxAccessTokenExpires)
			if err != nil {
				return rp, err
			}

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

type ResponseCancelPay struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	BillNo  string `json:"bill_no"`
}

// 取消支付
func CancelPay(openid string, billNo string) (*ResponseCancelPay, error) {
	req := NewHttpRequest()

	requestData := make(map[string]interface{})
	requestData["openid"] = openid                       //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
	requestData["appid"] = os.Getenv("WXPAY_APPID")      //"wx831355257c862ac2"
	requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892"
	requestData["ts"] = time.Now().Unix()
	requestData["zone_id"] = "1"
	requestData["pf"] = "android"
	requestData["bill_no"] = billNo
	//requestData["pay_item"] = "钻石"

	requestData["sig"] = MakeGetBalanceSig(requestData, cancelPayUri)
	requestData["access_token "] = wxAccessToken

	url := "https://api.weixin.qq.com" + cancelPayUri + "?access_token=" + wxAccessToken
	//url := "https://api.weixin.qq.com/cgi-bin/midas/sandbox/cancelpay?access_token=" + accessToken
	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(ResponseCancelPay)
		resp.UnmarshalBody(res)
		//log.Warnf("%#v", res)
		return res, nil
	}
	return nil, nil
}

type ResponsePresent struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	Balance int    `json:"balance"`
	BillNo  string `json:"bill_no"`
}

// 赠送
func Present(openid string, billNo string, presendCount int) (*ResponsePresent, error) {
	req := NewHttpRequest()

	requestData := make(map[string]interface{})
	requestData["openid"] = openid                       //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
	requestData["appid"] = os.Getenv("WXPAY_APPID")      //"wx831355257c862ac2"
	requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892"
	requestData["ts"] = time.Now().Unix()
	requestData["zone_id"] = "1"
	requestData["pf"] = "android"
	requestData["bill_no"] = billNo
	requestData["present_counts"] = presendCount

	requestData["sig"] = MakeGetBalanceSig(requestData, presentUri)
	requestData["access_token "] = wxAccessToken

	url := "https://api.weixin.qq.com" + presentUri + "?access_token=" + wxAccessToken
	//url := "https://api.weixin.qq.com/cgi-bin/midas/sandbox/present?access_token=" + accessToken
	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(ResponsePresent)
		resp.UnmarshalBody(res)
		//log.Warnf("%#v", res)
		return res, nil
	}
	return nil, nil
}
