package main

import (
	"../log"
	"../mod"
	"../nt"
	"../rpc"
	"../utils"
	"./pb"
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
	"strings"
)

var (
	ErrFailedFindUserAgent = errors.New("failed to find agent by user")
	ErrFailedFindLobby     = errors.New("failed to find agent by id")
	ErrRedisLuaError       = errors.New("redis lua return invalid value")
)

func decrypt(c *gin.Context, gr *dbdzRequest) error {

	body, _ := c.GetRawData()
	str := fmt.Sprintf("%s", body)
	log.Debug(">>>>>>>>decrypt ", zap.Any("data", str))
	encryptString := strings.Replace(strings.Replace(str[2:len(str)], "-", "+", -1), "_", "/", -1)
	decbyte, err := base64.RawStdEncoding.DecodeString(encryptString)
	if err != nil {
		log.Debug(">>>>>>>>decrypt RawStdEncoding.DecodeString", zap.Error(err))
		return err
	}
	json_, err := aesDecrypt(decbyte, checkAesKey(aesKeyDefValue))
	log.Debug("json", zap.String("aesDecrypt", fmt.Sprintf("%s", json_)))
	if err != nil {
		log.Debug("Encrypt aesDecrypt")
		return err
	}

	//去除空字符传才能json解析
	cut_num := 0 //需要截取的位数
	for i := len(json_) - 1; i >= 0; i-- {
		if json_[i] == 0 {
			cut_num++
		} else {
			break
		}
	}

	if err := json.Unmarshal(json_[:len(json_)-cut_num], gr); err != nil {
		log.Debug("json.Unmarshal")
		return err
	}
	log.Debug("json", zap.Any("data", gr))

	return nil
}

func LoadRedisLua() error {
	var err error
	sha_wallet_transfer, err = nt.Rdb.ScriptLoad(wallet_transfer).Result()
	return err
}

// 创建 error 映射，返回映射的条目
func BuildErrors() int {
	for k, v := range pb.Ec_name {
		E[pb.Ec(k)] = errors.New(v)
	}
	E[pb.Ec_SUCCEED] = nil

	return len(E)
}

func ConvertBalance(balance float64) float64 {
	return balance / 100
}

func BalanceToPlatform(balance float64) float64 {
	return balance * 100
}

func ConvertAmount(amount float64) int64 {
	return decimal.NewFromFloat(amount).Mul(decimal.NewFromFloat(100)).IntPart()
}

func GetUserAgent(guid uint64) (string, error) {
	agent, err := mod.GetUserAgent(guid)
	if nil != err {
		return "", err
	}
	for _, conf := range nt.DynConf.Lobbies {
		if conf.Id == agent {
			return "http://" + conf.RpcAddr + "/rpc", nil
		}
	}
	return "", ErrFailedFindUserAgent
}

// 通知玩家金币变动
// @guid
// @delta
//
// 重新定义指令 wallet_transfer
// 参数 guid, delta
func RpcNotifyBalanceChange(guid uint64, delta, newBalance int64) error {
	addr, err := GetUserAgent(guid)
	if nil != err {
		return err
	}
	args := rpc.RpcArgs{
		Cmd: "wallet_transfer",
		Params: utils.H{
			"guid":       guid,
			"delta":      delta,
			"newBalance": newBalance,
		},
	}
	res := rpc.RpcResult{}
	return rpc.RpcRequest(addr, &args, &res)
}

// 修改金币并增加注单记录
func UpdateTransferStatus(guid uint64, delta int64, transferId string, val interface{}) ([]interface{}, error) {
	keys := []string{
		mod.KUserInfo(guid),
		mod.KDBDZTransferIdKey(AgentName),
		transferId,
	}
	args := []interface{}{
		delta,
		val,
	}
	r, err := nt.Rdb.EvalSha(sha_wallet_transfer, keys, args...).Result()
	if nil != err {
		return nil, err
	}
	res, ok := r.([]interface{})
	if !ok {
		return nil, ErrRedisLuaError
	}
	return res, nil
}

func checkAesKey(strKey string) []byte {
	keyLen := len(strKey)
	arrKey := []byte(strKey)
	if keyLen >= 32 {
		return arrKey[:32]
	}
	if keyLen >= 24 {
		return arrKey[:24]
	}
	if keyLen >= 16 {
		return arrKey[:16]
	}
	tmp := make([]byte, 16)
	for i := 0; i < 16; i++ {
		if i < keyLen {
			tmp[i] = arrKey[i]
		} else {
			tmp[i] = '0'
		}
	}
	return tmp
}
func aesEncrypt(plaintext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		fmt.Println("err=", err)
		return nil, errors.New("invalid decrypt key")
	}
	blockSize := block.BlockSize()
	plaintext = PKCS5Padding(plaintext, blockSize)
	iv := []byte(aesIvDefValue)
	blockMode := cipher.NewCBCEncrypter(block, iv)
	ciphertext := make([]byte, len(plaintext))
	blockMode.CryptBlocks(ciphertext, plaintext)
	return ciphertext, nil
}
func PKCS5Padding(src []byte, blockSize int) []byte {
	padding := blockSize - len(src)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padtext...)
}
func aesDecrypt(ciphertext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, errors.New("invalid decrypt key")
	}
	blockSize := block.BlockSize()
	if len(ciphertext) < blockSize {
		return nil, errors.New("ciphertext too short")
	}
	iv := []byte(aesIvDefValue)
	if len(ciphertext)%blockSize != 0 {
		return nil, errors.New("ciphertext is not a multiple of the block size")
	}
	blockModel := cipher.NewCBCDecrypter(block, iv)
	plaintext := make([]byte, len(ciphertext))
	blockModel.CryptBlocks(plaintext, ciphertext)
	return plaintext, nil
}
