package GoUtil

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	crand "crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/gob"
	"encoding/hex"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"reflect"
	"server/pkg/github.com/name5566/leaf/log"
	"strconv"
	"strings"
	"sync"
	"time"
)

var bufferPool = sync.Pool{
	New: func() interface{} {
		return bytes.NewBuffer(make([]byte, 0, 128*1024))
	},
}

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

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

const (
	SECRET_KEY   = ")VQbB(vpy=U(wcp)"
	CONDITION_EQ = "="  // 等于
	CONDITION_GT = ">"  // 大于
	CONDITION_LT = "<"  // 小于
	CONDITION_GE = ">=" // 大于等于
	CONDITION_LE = "<=" // 小于等于

	LETTER = "GhCvgqSNTUMVeRfwakiYmcxWKtJQpZrDIBXnPyLsAFdzjHbulE"
)

// 加密字符串
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 String(a interface{}) string {
	if a == nil {
		return ""
	}
	switch v := a.(type) {
	case int:
		return strconv.Itoa(v)
	case int32:
		return strconv.Itoa(int(v))
	case int64:
		return strconv.Itoa(int(v))
	case float64:
		return strconv.FormatFloat(v, 'f', -1, 64)
	case string:
		return v
	}
	return ""
}

func GobMarshal(data interface{}) ([]byte, error) {
	buf := bufferPool.Get().(*bytes.Buffer)
	buf.Reset() // 清空之前的数据
	encode := gob.NewEncoder(buf)
	err := encode.Encode(data)
	if err != nil {
		bufferPool.Put(buf) // 即使出错也要归还
		return nil, err
	}
	result := make([]byte, buf.Len())
	copy(result, buf.Bytes())
	bufferPool.Put(buf) // 归还到对象池
	return result, 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 {
	if uid <= 100000 {
		return uid
	}
	if uid <= 100000000 {
		return uid / 100000
	}
	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
}

func Compare(x int, condition string, y int) bool {
	switch condition {
	case CONDITION_EQ:
		return x == y
	case CONDITION_GT:
		return x > y
	case CONDITION_LT:
		return x < y
	case CONDITION_GE:
		return x >= y
	case CONDITION_LE:
		return x <= y
	default:
		return false
	}
}

func UniKey(seed string) string {
	hash := md5.New()
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	io.WriteString(hash, seed+timestamp)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func GetCatnipLockKey(Uid, GameId int) string {
	return fmt.Sprintf("catnip_lock_%d_%d", Uid, GameId)
}

func Rand6DigitNumber() string {
	n := rand.Intn(1000000)
	return fmt.Sprintf("%06d", n)
}

func Rand8DigitNumber() string {
	n := rand.Intn(100000000)
	return fmt.Sprintf("%08d", n)
}

func UniqueInts(input []int) []int {
	seen := make(map[int]struct{})
	result := make([]int, 0, len(input))
	for _, v := range input {
		if _, ok := seen[v]; !ok {
			seen[v] = struct{}{}
			result = append(result, v)
		}
	}
	return result
}

/*
#codebase: GoUtil
修改函数UniqueStringFromInt

功能说明：
将整数转换为包含字母和数字的唯一字符串

算法步骤：
1. 将输入整数格式化为5位数字符串（不足前补0）
2. 分割字符串：前2位、中2位、最后1位
3. 将各段转为整数，作为字母表索引
4. 从预定义字母表中选择对应字符
5. 随机生成2个数字字符
6. 随机插入数字字符到字母串中
7. 返回最终唯一标识字符串
*/

func UniqueStringFromInt(n int) string {
	n = n % 100000 // 确保n在0-99999范围内
	str := fmt.Sprintf("%05d", n)
	a1 := str[0:2]
	a2 := str[2:4]
	a3 := str[4:5]

	s1, _ := strconv.Atoi(a1)
	s2, _ := strconv.Atoi(a2)
	s3, _ := strconv.Atoi(a3)

	// 修改索引计算逻辑
	var letter1, letter2 string
	if s1 >= len(LETTER) {
		letter1 = string(LETTER[s1%len(LETTER)]) + strconv.Itoa(s1/len(LETTER))
	} else {
		letter1 = string(LETTER[s1])
	}

	if s2 >= len(LETTER) {
		idx := (s2) % len(LETTER)
		letter2 = string(LETTER[idx]) + strconv.Itoa(s2/len(LETTER))
	} else {
		letter2 = string(LETTER[s2])
	}

	letter3 := string(LETTER[s3+20])
	letter := fmt.Sprintf("%s%s%s", letter1, letter2, letter3)
	lastLetter := 5 - len(letter)
	indices := rand.Perm(8)[:2]
	chars := []byte{byte('2' + indices[0]), byte('2' + indices[1])}
	if lastLetter > 0 {
		for i := 0; i < lastLetter; i++ {
			insertPos1 := rand.Intn(len(letter) + 1)
			letter = letter[:insertPos1] + string(chars[0]) + letter[insertPos1:]
		}
	}
	pos := rand.Intn(len(LETTER))
	letter += string(LETTER[pos])
	return fmt.Sprintf("%s-%s", letter[:3], letter[3:])
}

// 反解析 UniqueStringFromInt 生成的字符串，返回原始整数（0-99999），失败返回 -1
func ParseUniqueStringToInt(s string) int {
	arr := strings.Split(s, "-")
	// 去除字符串中大于1的数字
	s1 := arr[2] + arr[3]
	s1 = s1[:len(s1)-1] // 去掉最后一个字符
	s2 := ""
	for _, ch := range s1 {
		if ch < '2' || ch > '9' {
			s2 += string(ch)
		}
	}
	index1 := 0
	s3 := ""
	for i := 0; i < len(s2); i++ {
		index := strings.Index(LETTER, string(s2[i]))

		if i < len(s2)-1 && s2[i+1] == '1' {
			index += len(LETTER)
			i++
		}
		index1++
		if i == len(s2)-1 {
			index -= 20 // 最后一位是字母，减去20
			s3 += fmt.Sprintf("%d", index)
		} else {
			s3 += fmt.Sprintf("%02d", index)
		}

	}
	return Int(s3)
}

func GenerateShuffledAlphabet() string {
	// 包含所有大小写字母的字符串
	alphabet := "abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ"

	// 转换为字节切片以便打乱
	bytes := []byte(alphabet)

	// 使用当前时间作为随机种子
	rand.Seed(time.Now().UnixNano())

	// Fisher-Yates 洗牌算法
	for i := len(bytes) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		bytes[i], bytes[j] = bytes[j], bytes[i]
	}

	return string(bytes)
}

// 根据IP获取国家名称
func GetCountryByIP(ip string) (string, error) {
	return "", nil
	// resp, err := http.Get("https://ipapi.co/" + ip + "/country_name/")
	// if err != nil {
	// 	return "", err
	// }
	// defer resp.Body.Close()
	// buf := new(bytes.Buffer)
	// buf.ReadFrom(resp.Body)
	// return strings.TrimSpace(buf.String()), nil
}

// 根据国家名称获取ISO 3166-1国家码
func GetISOCodeByCountry(country string) (string, error) {
	// 简单映射，可以扩展为更完整的映射表
	countryMap := map[string]string{
		"Afghanistan":            "004", // 阿富汗
		"Albania":                "008", // 阿尔巴尼亚
		"Algeria":                "012", // 阿尔及利亚
		"Angola":                 "024", // 安哥拉
		"Argentina":              "032", // 阿根廷
		"Austria":                "040", // 奥地利
		"Azerbaijan":             "031", // 阿塞拜疆
		"Bahrain":                "048", // 巴林
		"Bangladesh":             "050", // 孟加拉国
		"Belgium":                "056", // 比利时
		"Bolivia":                "068", // 玻利维亚
		"Bosnia and Herzegovina": "070", // 波斯尼亚和黑塞哥维那
		"Brazil":                 "076", // 巴西
		"Bulgaria":               "100", // 保加利亚
		"Canada":                 "124", // 加拿大
		"Chile":                  "152", // 智利
		"China":                  "156", // 中国
		"Colombia":               "170", // 哥伦比亚
		"Costa Rica":             "188", // 哥斯达黎加
		"Croatia":                "191", // 克罗地亚
		"Cuba":                   "192", // 古巴
		"Denmark":                "208", // 丹麦
		"Ecuador":                "218", // 厄瓜多尔
		"Egypt":                  "818", // 埃及
		"Ethiopia":               "231", // 埃塞俄比亚
		"Finland":                "246", // 芬兰
		"France":                 "250", // 法国
		"Germany":                "276", // 德国
		"Ghana":                  "288", // 加纳
		"Greece":                 "300", // 希腊
		"Hungary":                "348", // 匈牙利
		"India":                  "356", // 印度
		"Indonesia":              "360", // 印度尼西亚
		"Iran":                   "364", // 伊朗
		"Iraq":                   "368", // 伊拉克
		"Italy":                  "380", // 意大利
		"Japan":                  "392", // 日本
		"Jordan":                 "400", // 约旦
		"Kenya":                  "404", // 肯尼亚
		"Kuwait":                 "414", // 科威特
		"Lebanon":                "422", // 黎巴嫩
		"Malaysia":               "458", // 马来西亚
		"Mexico":                 "484", // 墨西哥
		"Morocco":                "504", // 摩洛哥
		"Nigeria":                "566", // 尼日利亚
		"Norway":                 "578", // 挪威
		"Pakistan":               "586", // 巴基斯坦
		"Peru":                   "604", // 秘鲁
		"Philippines":            "608", // 菲律宾
		"Poland":                 "616", // 波兰
		"Portugal":               "620", // 葡萄牙
		"Qatar":                  "634", // 卡塔尔
		"Romania":                "642", // 罗马尼亚
		"Russia":                 "643", // 俄罗斯
		"Saudi Arabia":           "682", // 沙特阿拉伯
		"South Africa":           "710", // 南非
		"South Korea":            "410", // 韩国
		"Spain":                  "724", // 西班牙
		"Sweden":                 "752", // 瑞典
		"Switzerland":            "756", // 瑞士
		"Thailand":               "764", // 泰国
		"Turkey":                 "792", // 土耳其
		"Ukraine":                "804", // 乌克兰
		"United Kingdom":         "826", // 英国
		"United States":          "840", // 美国
		"Vietnam":                "704", // 越南
		"Zimbabwe":               "716", // 津巴布韦
	}
	if code, ok := countryMap[country]; ok {
		return code, nil
	}
	return "", fmt.Errorf("country code not found for %s", country)
}

// 综合函数：根据IP获取ISO 3166-1国家码
func GetISOCodeByIP(ip string) (string, error) {
	country, err := GetCountryByIP(ip)
	if err != nil {
		return "", err
	}
	return GetISOCodeByCountry(country)
}

func GetVarKey(Uid int) string {
	return fmt.Sprintf("var_%d", Uid)
}

const (
	PROJECT_ID              = "20659"
	ACCESS_ID               = "a3d8c1f0e5b72a49"
	NOTIFICATION_SECRET_KEY = "K8pYrR6fXcVzWbAqN3mHsD4gJtL9iUvO1"
)

func NotifyPlayer(uid, pushid int, title, content string) {
	if uid == 0 {
		return
	}
	url := "https://tygapi-new.tuyooglobal.com/api/push/ga/push_message/project_trigger"
	method := "POST"
	executeId := fmt.Sprintf("%s_%s", PROJECT_ID, Rand8DigitNumber()+Rand8DigitNumber())
	payload := strings.NewReader(`[
    {
        "projectId": "` + PROJECT_ID + `",
        "platform": "firebasepush",
        "pushId": "` + PROJECT_ID + `_` + fmt.Sprintf("%08d", pushid) + `",
		"executeId": "` + executeId + `",
        "environment": "production",
        "title": "` + title + `",
        "body": "` + content + `",
        "userId": [
            "` + strconv.Itoa(uid) + `"
        ]
    }
]`)

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		fmt.Println(err)
		return
	}
	d, _ := time.ParseDuration("30m")
	timestamp := time.Now().Add(d).Unix()

	var strBuilder strings.Builder
	strBuilder.WriteString("Access-Id=" + ACCESS_ID + "&Random=a2dS8Iyak03Ma91JC1xR&Secret-Type=forever&Sign-Type=sha256&Timestamp=")
	strBuilder.WriteString(strconv.Itoa(int(timestamp)))
	strBuilder.WriteString(":" + NOTIFICATION_SECRET_KEY)

	m := sha256.New()
	m.Write([]byte(strBuilder.String()))
	signature := hex.EncodeToString(m.Sum(nil))

	req.Header.Add("Access-Id", ACCESS_ID)
	req.Header.Add("Secret-Type", "forever")
	req.Header.Add("Sign-Type", "sha256")
	req.Header.Add("Random", "a2dS8Iyak03Ma91JC1xR")
	req.Header.Add("Timestamp", strconv.Itoa(int(timestamp)))
	req.Header.Add("Signature", signature)
	req.Header.Add("Content-Type", "application/json")
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()

	body, err := io.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	log.Debug("notification send uid %d, type %d , res %s", uid, pushid, string(body))
}
