package common

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"fmt"
	"mongo.games.com/goserver/core/logger"
	"regexp"
	"strconv"
)

var key = []byte("kjh-vgjhhionoommmkokmokoo$%JH")

// 加密
func EnCrypt(orig []byte) (str string) {
	defer func() {
		err := recover()
		if err != nil {
			logger.Logger.Errorf("EnCrypt %v Error %v", string(orig), err)
			str = string(orig)
		}
	}()
	//将秘钥中的每个字节累加,通过sum实现orig的加密工作
	sum := 0
	for i := 0; i < len(key); i++ {
		sum += int(key[0])
	}

	//给明文补码
	var pkcs_code = PKCS5Padding(orig, 8)

	//通过秘钥，对补码后的明文进行加密
	for j := 0; j < len(pkcs_code); j++ {
		pkcs_code[j] += byte(sum)
	}
	//base64.URLEncoding.EncodeToString()
	return base64.URLEncoding.EncodeToString(pkcs_code)
}

// 补码
func PKCS5Padding(orig []byte, size int) []byte {
	//计算明文的长度
	length := len(orig)
	padding := size - length%size
	//向byte类型的数组中重复添加padding
	repeats := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(orig, repeats...)
}

// 解密
func DeCrypt(text string) (str string) {
	defer func() {
		err := recover()
		if err != nil {
			logger.Logger.Errorf("DeCrypt %v Error %v", text, err)
			str = text
		}
	}()
	//orig, err := base64.StdEncoding.DecodeString(text)
	orig, err := base64.URLEncoding.DecodeString(text)
	if err != nil {
		return "密文类型错误"
	}
	sum := 0
	for i := 0; i < len(key); i++ {
		sum += int(key[0])
	}

	//解密
	for j := 0; j < len(orig); j++ {
		orig[j] -= byte(sum)
	}

	//去码
	var pkcs_unCode = PKCS5UnPadding(orig)
	return string(pkcs_unCode)
}

// 去码
func PKCS5UnPadding(orig []byte) []byte {
	//获取最后一位补码的数字
	var tail = int(orig[len(orig)-1])
	return orig[:(len(orig) - tail)]
}

var aesRule, _ = regexp.Compile(`^[0-9]+$`)

const (
	aeskey = "DoNotEditThisKeyDoNotEditThisKey" // 加密的密钥,绝不可以更改
)

// 下面的字符串,也绝不可以更改
var defaultLetters = []rune("idjGfiRogsFnkdKgokdfgdow07u6978uxcvvLiPiDfjafOd2fuFJYYGBJuykbvfk")

func AesEncrypt(origDataStr string) (str string) {
	defer func() {
		err := recover()
		if err != nil {
			logger.Logger.Errorf("AesEncrypt %v Error %v", origDataStr, err)
			str = origDataStr
		}
	}()
	strlen := len(origDataStr)
	b := aesRule.MatchString(origDataStr)
	//不全是数字，或长度为零，不加密
	if !b || strlen == 0 {
		return origDataStr
	}
	phonenum, errint := strconv.Atoi(origDataStr)
	if errint != nil {
		return origDataStr
	}

	text := []byte(origDataStr)
	//指定加密、解密算法为AES，返回一个AES的Block接口对象
	block, err := aes.NewCipher([]byte(aeskey))
	if err != nil {
		panic(err)
	}
	//指定计数器,长度必须等于block的块尺寸
	iv := string(defaultLetters[phonenum%(len(defaultLetters))])
	count := []byte(fmt.Sprintf("%016v", iv))
	//指定分组模式
	blockMode := cipher.NewCTR(block, count)
	//执行加密、解密操作
	message := make([]byte, len(text))
	blockMode.XORKeyStream(message, text)
	//返回明文或密文
	return fmt.Sprintf("%v%v", iv, base64.StdEncoding.EncodeToString(message))
	//return base64.StdEncoding.EncodeToString(message)
}

func AesDecrypt(cryptedstr string) (str string) {
	defer func() {
		err := recover()
		if err != nil {
			logger.Logger.Errorf("AesDecrypt %v Error %v", cryptedstr, err)
			str = cryptedstr
		}
	}()
	strlen := len(cryptedstr)
	b := aesRule.MatchString(cryptedstr)
	//全是数字，或长度为零，不解密
	if b || strlen == 0 {
		return cryptedstr
	}

	iv := cryptedstr[:1]
	str = cryptedstr[1:]
	text, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		logger.Logger.Errorf("AesDecrypt %v  Err:%v", cryptedstr, err)
		return cryptedstr
	}

	//指定加密、解密算法为AES，返回一个AES的Block接口对象
	block, err := aes.NewCipher([]byte(aeskey))
	if err != nil {
		panic(err)
	}
	//指定计数器,长度必须等于block的块尺寸
	count := []byte(fmt.Sprintf("%016v", iv))
	//指定分组模式
	blockMode := cipher.NewCTR(block, count)
	//执行加密、解密操作
	message := make([]byte, len(text))
	blockMode.XORKeyStream(message, text)
	//返回明文或密文
	return string(message)
}
