package GoUtil

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	crand "crypto/rand"
	"encoding/base64"
	"encoding/gob"
	"fmt"
	"io"
	"math/rand"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// 实例化一个通过字符串映射函数切片的map
var eventByName = make(map[string][]*EventObj)

type EventObj struct {
	Callback func([]interface{})
	Obj      interface{}
}

const (
	SECRET_KEY = ")VQbB(vpy=U(wcp)"
)

// 加密字符串
func Encrypt(plainText string) (string, error) {
	block, err := aes.NewCipher([]byte(SECRET_KEY))
	if err != nil {
		return "", err
	}

	cipherText := make([]byte, aes.BlockSize+len(plainText))
	iv := cipherText[:aes.BlockSize]
	if _, err := io.ReadFull(crand.Reader, iv); err != nil {
		return "", err
	}

	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(cipherText[aes.BlockSize:], []byte(plainText))

	return base64.URLEncoding.EncodeToString(cipherText), nil
}

// 解密字符串
func Decrypt(cipherText string) (string, error) {
	cipherTextBytes, err := base64.URLEncoding.DecodeString(cipherText)
	if err != nil {
		return "", err
	}

	block, err := aes.NewCipher([]byte(SECRET_KEY))
	if err != nil {
		return "", err
	}

	if len(cipherTextBytes) < aes.BlockSize {
		return "", fmt.Errorf("cipherText too short")
	}

	iv := cipherTextBytes[:aes.BlockSize]
	cipherTextBytes = cipherTextBytes[aes.BlockSize:]

	stream := cipher.NewCFBDecrypter(block, iv)
	stream.XORKeyStream(cipherTextBytes, cipherTextBytes)

	return string(cipherTextBytes), nil
}

func (o *EventObj) isEqual(tar *EventObj) bool {
	if reflect.ValueOf(o.Callback).Pointer() == reflect.ValueOf(tar.Callback).Pointer() && o.Obj == tar.Obj {
		return true
	}
	return false
}

// 注册事件，提供事件名和回调函数
func RegisterEvent(name string, callback func([]interface{}), Obj interface{}) {

	eo := new(EventObj)
	eo.Callback = callback
	eo.Obj = Obj
	// 通过名字查找事件列表
	list := eventByName[name]

	// 在列表切片中添加函数
	list = append(list, eo)

	// 将修改的事件列表切片保存回去
	eventByName[name] = list
}

// 调用事件
func CallEvent(name string, param []interface{}) {

	// 通过名字找到事件列表
	list := eventByName[name]

	// 遍历这个事件的所有回调
	for _, eo := range list {
		// 传入参数调用回调
		eo.Callback(param)
	}
}

func RemoveEvent(name string, callback func([]interface{}), Obj interface{}) {
	// 通过名字找到事件列表
	list := eventByName[name]
	j := 0
	eo := new(EventObj)
	eo.Callback = callback
	eo.Obj = Obj
	// 遍历这个事件的所有回调
	for _, v := range list {
		if !v.isEqual(eo) {
			list[j] = v
			j++
		}
	}
	eventByName[name] = list[:j]
}

func DeleteEleByValue(list []int, ele int) []int {
	j := 0
	for _, v := range list {
		if v != ele {
			list[j] = v
			j++
		}
	}
	ret := list[:j]
	return ret
}

func BoolToInt32(b bool) int32 {
	if b {
		return 1
	}
	return 0
}

func IfTrue(a bool, b, c interface{}) interface{} {
	if a {
		return b
	}
	return c
}

func Int64(a interface{}) int64 {
	if a == nil {
		return 0
	}
	switch v := a.(type) {
	case int:
		return int64(v)
	case int32:
		return int64(v)
	case int64:
		return v
	case float64:
		return int64(v)
	}
	return 0
}

func Int(a interface{}) int {
	if a == nil {
		return 0
	}
	switch v := a.(type) {
	case int:
		return v
	case int32:
		return int(v)
	case int64:
		return int(v)
	case float64:
		return int(v)
	case string:
		r, err := strconv.Atoi(v)
		if err != nil {
			return 0
		}
		return r
	}
	return 0
}

func GobMarshal(data interface{}) ([]byte, error) {
	var buf bytes.Buffer
	encode := gob.NewEncoder(&buf)
	err := encode.Encode(data)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func GobUnmarshal(data []byte, obj interface{}) error {
	decode := gob.NewDecoder(bytes.NewReader(data))
	err := decode.Decode(obj)
	if err != nil {
		return err
	}
	return nil
}

func GetServerIdByUid(uid int) int {
	return int((uid % 100000000) / 100000)
}

func CreateOrderSn(uid int) string {
	Now := time.Now()
	return "order_" + strconv.Itoa(uid) + "_" + Now.Format("20060102150405") + RandString(6)
}

// 生成指定长度的随机字符串
func RandString(n int) string {
	const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[r.Intn(len(letters))]
	}
	return string(b)
}

// 生成索要卡牌唯一id
func CreateCardId(From, To, CardId int) string {
	return fmt.Sprintf("%d_%d_%d_%d_%s", From, To, CardId, Now(), RandString(3))
}

func SplitInt(str, sep string) []int {
	var ret []int
	for _, v := range strings.Split(str, sep) {
		ret = append(ret, Int(v))
	}
	return ret
}
