package utils

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// 此函数将指定的结构体成员值更新到结构体中
func SetStructValueByType(s interface{}, columnType string, columnValue interface{}) error {
	columnValueV := reflect.ValueOf(columnValue)
	var setValue reflect.Value
	var flag = false
	v := reflect.ValueOf(s)
	for i, n := 0, v.Elem().NumField(); i < n; i++ {
		if v.Elem().Type().Field(i).Name == columnType {
			setValue = v.Elem().Field(i)
			flag = true
			break
		}
	}
	if !flag {
		return errors.New("struct is not type:")
	} else if !setValue.CanSet() {
		return errors.New("setValue.CanSet is false")
	} else if setValue.Kind() != columnValueV.Kind() {
		return errors.New("struct field and value of type is error")
	}
	switch columnValueV.Kind() {
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
		setValue.SetInt(int64(columnValueV.Int()))
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		setValue.SetUint(uint64(columnValueV.Uint()))
	case reflect.Float32, reflect.Float64:
		setValue.SetFloat(float64(columnValueV.Float()))
	case reflect.String:
		setValue.SetString(columnValueV.String())
	case reflect.Struct:
		setValue.Set(columnValueV)
	default:
		return errors.New("columnValue err for:" + columnType)
	}
	return nil
}

func JoinInts(ids []int, spilt string) string {
	var idStrings []string = make([]string, len(ids))
	for i := 0; i < len(ids); i++ {
		idStrings[i] = fmt.Sprintf("%v", ids[i])
	}
	return strings.Join(idStrings, spilt)
}
func JoinInt8s(ids []int8, spilt string) string {
	var idStrings []string = make([]string, len(ids))
	for i := 0; i < len(ids); i++ {
		idStrings[i] = fmt.Sprintf("%v", ids[i])
	}
	return strings.Join(idStrings, spilt)
}
func JoinInt64s(ids []int64, spilt string) string {
	var idStrings []string = make([]string, len(ids))
	for i := 0; i < len(ids); i++ {
		idStrings[i] = fmt.Sprintf("%v", ids[i])
	}
	return strings.Join(idStrings, spilt)
}

//判断是否为空
func IsNil(i interface{}) bool {
	vi := reflect.ValueOf(i)
	if vi.Kind() == reflect.Ptr {
		return vi.IsNil()
	}
	return false
}

func JsonUnmarshal(jsonData string, v interface{}) {
	if len(jsonData) == 0 {
		return
	}
	if e := json.Unmarshal([]byte(jsonData), v); e != nil {
		log.Error("json.unmarshal error data:", jsonData, e)
	}
}

func JsonAssertString(v interface{}) string {
	if data, e := json.Marshal(v); e == nil {
		return string(data)
	}
	return ""
}

//深度拷贝
func DeepCopy(dst, src interface{}) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(src); err != nil {
		return err
	}
	return gob.NewDecoder(&buf).Decode(dst)
}

//深度拷贝
func JsonDeepCopy(dst, src interface{}) error {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(src); err != nil {
		return err
	}
	return json.NewDecoder(&buf).Decode(dst)
}

//检查版本信息
func ValidVersion(current, compare string) bool {
	curVersions := strings.Split(current, ".")
	comVersions := strings.Split(compare, ".")
	for i := range curVersions {
		//v1,v2:=strings.TrimSpace(curVersions[i]),""
		v1, _ := strconv.ParseInt(strings.TrimSpace(curVersions[i]), 10, 64)
		var v2 int64
		if i < len(comVersions) {
			v2, _ = strconv.ParseInt(strings.TrimSpace(comVersions[i]), 10, 64)
		}
		if v1 == 0 && v2 == 0 {
			continue
		}
		if v1 >= v2 {
			return true
		}
		if v1 < v2 {
			return false
		}
	}
	return false
}

// 统计某函数执行时间
// 使用方式
// defer utils.Profiling("test")()
func Profiling(msg string) func() {
	start := time.Now()
	return func() {
		log.Info(fmt.Sprintf("%s[%s]:%s", msg, "use", time.Since(start)))
	}
}

//合并字典
func MergeMap(to map[string]interface{}, from map[string]interface{}) {
	for k, v := range from {
		to[k] = v
	}
}

func GetPageInfo(pageIndex, pageSize int) (offset, size int) {
	if pageSize == 0 {
		pageSize = 20
	}
	if pageIndex == 0 {
		pageIndex = 1
	}
	offset = (pageIndex - 1) * pageSize
	size = pageSize
	return
}