package gameapi

import (
	"../log"
	"../mod"
	pb "../protos"
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func DBDZ_Enter_game(guid string, gameParam []string, res *pb.S_EnterGame) {
	//余额 从钱包里取 不走这里
	if len(gameParam) != 2 {
		res.Ec = SYS_GAME_PARAM_ERROR
		return
	}
	gType := gameParam[0]
	mType := gameParam[1]
	gt := getToken{login_Action, time.Now().UnixNano() / 1e6, DbdzAgent, guid, 0, "ch",
		gType, mType, DONT_USE_LOBBY, NO_MORE_GAME}
	var dr dbdzResponse

	if dBDZ_do_request(gt, &dr) {
		res.Ec = SUCCESS
		res.Url = dr.Path
		res.GameParam = gameParam
		log.Debug("<<< DBDZ_Enter_game gameParam", zap.Any("data", res))
	} else {
		res.Ec = SYS_LOGIN_FAILED
	}
}

func DBDZ_Leave_game(guid string, balance *pb.S_Ntf_UserBalance, res *pb.S_LeaveGame) {

	res.Ec = SUCCESS
	// 取得余额
	guid_, err := strconv.ParseUint(guid, 10, 64)
	if err != nil {
		log.Debug("DBDZ_Leave_game ParseUint err", zap.Error(err))
		balance.Balance = 0
		return
	}

	sbalance, err := mod.GetUserAttr(guid_, "balance")
	if err != nil {
		log.Debug("DBDZ_Leave_game GetUserAttr balance err", zap.Error(err))
		balance.Balance = 0
		return
	}
	balance.Balance, err = strconv.ParseInt(sbalance, 10, 64)
	if err != nil {
		balance.Balance = 0
		log.Error("DBDZ_Leave_game ParseUint err", zap.Error(err))
		return
	}

	log.Debug("DBDZ_Leave_game getBalance success", zap.String("guid", guid), zap.Int64("Balance", balance.Balance))
}

func dBDZ_do_request(param interface{}, res *dbdzResponse) bool {

	log.Debug("DBDZ_do_request param", zap.Any("data", param))
	bytesData, err := json.Marshal(param)
	if err != nil {
		log.Debug("DBDZ_do_request json.Marshal", zap.Error(err))
		return false
	}

	encbyte, err := aesEncrypt(bytesData, checkAesKey(AesKeyDefValue))
	if err != nil {
		log.Debug("DBDZ_do_request aesEncrypt", zap.Error(err))
		return false
	}

	encryptString := strings.Replace(strings.Replace(base64.RawStdEncoding.EncodeToString(encbyte), "+", "-", -1), "/", "_", -1)
	log.Debug("DBDZ_do_request encryptString", zap.Any("data", encryptString))

	payload := strings.NewReader("dc=" + DC + "&x=" + encryptString)

	req, err := http.NewRequest("POST", Dbdz_url, payload)
	if err != nil {
		log.Debug("DBDZ_do_request NewRequest", zap.Error(err))
		return false
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}

	client := &http.Client{Transport: tr}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("cache-control", "no-cache")
	resp, err := client.Do(req)
	if err != nil {
		log.Debug("DBDZ_do_request client.Do", zap.Error(err))
		return false
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Debug("DBDZ_do_request ioutil.ReadAll", zap.String("data", fmt.Sprintf("%s", body)))
		return false
	}

	if err := json.Unmarshal(body, res); err != nil {
		log.Debug("DBDZ_do_request Unmarshal", zap.Error(err))
		return false
	}
	log.Debug("dBDZ_do_request", zap.Any("data", *res))
	if res.Status == DBDZ_SUCCESS {
		return true
	} else {
		return false
	}

}

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
}
