package lib

import (
	"gitdxz.51daxuetong.cn/go_dev/jjl-tools/tinodeService/store/types"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"golang.org/x/crypto/xtea"
	"io/ioutil"
	"net/http"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"unsafe"
)

func SizeStruct(data interface{}) int {
	return sizeof(reflect.ValueOf(data))
}
//uid加密函数 -- 客户端使用,服务端处理后返回给客户端的uid需要做加密处理
func GencodeUid(val int64) string {
	var src = make([]byte, 8)
	var dst = make([]byte, 8)
	binary.LittleEndian.PutUint64(src, uint64(val))
	var cipher *xtea.Cipher
	cipher, _ = xtea.NewCipher(getUidKey())
	cipher.Encrypt(dst, src)
	user := types.Uid(binary.LittleEndian.Uint64(dst))
	return user.UserId()
}
//字符串  622919054444728320 转成usr这种
func UidSEncodeNoErr(uid string) string {
	if uid == "" {
		return ""
	}
	if strings.Contains(uid, "usr") {
		return uid
	}
	uidI, err := strconv.ParseInt(uid, 10, 64)
	if err != nil {
		//logger.Error(gsfn, "fatal err", err, "uid", uid)
		return ""
	}
	return encodeUid(uidI)
}
//uid加密函数 -- 客户端使用,服务端处理后返回给客户端的uid需要做加密处理
func encodeUid(val int64) string {
	var src = make([]byte, 8)
	var dst = make([]byte, 8)
	binary.LittleEndian.PutUint64(src, uint64(val))
	var cipher *xtea.Cipher
	cipher, _ = xtea.NewCipher(getUidKey())
	cipher.Encrypt(dst, src)
	user := types.Uid(binary.LittleEndian.Uint64(dst))
	return user.UserId()
}

func sizeof(v reflect.Value) int {
	switch v.Kind() {
	case reflect.Map:
		sum := 0
		keys := v.MapKeys()
		for i := 0; i < len(keys); i++ {
			mapkey := keys[i]
			s := sizeof(mapkey)
			if s < 0 {
				return -1
			}
			sum += s
			s = sizeof(v.MapIndex(mapkey))
			if s < 0 {
				return -1
			}
			sum += s
		}
		return sum
	case reflect.Slice, reflect.Array:
		sum := 0
		for i, n := 0, v.Len(); i < n; i++ {
			s := sizeof(v.Index(i))
			if s < 0 {
				return -1
			}
			sum += s
		}
		return sum

	case reflect.String:
		sum := 0
		for i, n := 0, v.Len(); i < n; i++ {
			s := sizeof(v.Index(i))
			if s < 0 {
				return -1
			}
			sum += s
		}
		return sum

	case reflect.Ptr, reflect.Interface:
		p := (*[]byte)(unsafe.Pointer(v.Pointer()))
		if p == nil {
			return 0
		}
		return sizeof(v.Elem())
	case reflect.Struct:
		sum := 0
		for i, n := 0, v.NumField(); i < n; i++ {
			s := sizeof(v.Field(i))
			if s < 0 {
				return -1
			}
			sum += s
		}
		return sum

	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128,
		reflect.Int:
		return int(v.Type().Size())

	default:
		//fmt.Println("t.Kind() no found:", v.Kind())
	}

	return -1
}

/*
* 返回函数名
 */
func GetSysFuncName() string {
	pc, _, line, _ := runtime.Caller(1)
	f := runtime.FuncForPC(pc)
	res := "line:" + strconv.Itoa(line) + "||funcName:" + f.Name() + "||error:"
	return res
}

// type Uid uint64
type testJose struct {
	UserKey string `json:"uid_key"`
}

type configType struct {
	// 16-byte key for XTEA. Used to initialize types.UidGenerator.
	UidKey []byte `json:"uid_key"`
}

func getUidKey() []byte {
	test := testJose{UserKey: "la6YsO+bNX/+XIkOqc5Svw=="}
	jsonStr, err := json.Marshal(test)
	var config configType
	err = json.Unmarshal([]byte(jsonStr), &config)
	if err != nil {
		fmt.Println(err)
	}
	return config.UidKey
}

type AccessTokenResp struct {
	Code        int    `json:"code"`
	Errmsg      string `json:"errmsg"`
	AccessToken string `json:"access_token"`
	ExpiresIn   string `json:"expires_in"`
}


func RequestOnlineMap(url string) map[string]interface{} {
	client := http.Client{}
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Println("err 320 line: ", err)
	}
	// 添加请求头
	req.Header.Add("Content-type", "application/json;charset=utf-8")
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("err 327 line: ", err)
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("err 332 line: ", err)
	}
	//fmt.Println(string(b))

	resMap := make(map[string]interface{})
	err = json.Unmarshal(b, &resMap)
	return resMap
}
func Interface2Int(val interface{}) int {
	var res int
	res = 0
	switch val.(type) {
	case string:
		res, _ = strconv.Atoi(val.(string))
		break
	case int:
		res = val.(int)
		break
	case int64:
		tmp := strconv.FormatInt(val.(int64), 10)
		res, _ = strconv.Atoi(tmp)
		break
	case uint16:
		res = int(val.(uint16))
		break
	}

	return res
}
func Interface2String(val interface{}) string {
	var res string
	res = ""
	switch val.(type) {
	case int:
		res = strconv.Itoa(val.(int))
		break
	case string:
		res = val.(string)
		break
	case int64:
		res = strconv.FormatInt(val.(int64), 10)
		break
	}
	return res
}