package lib

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/nats-io/nats.go"

	"sort"
	"strconv"
	"strings"
	"time"
)

var Run_My_Server = false // 运行当期服务

// var DeviceRealSnMap map[string]int /*创建集合 */
var DeviceRealSnMap *sync.Map /*创建集合 */
var Nats *nats.Conn

func init() {
	//DeviceRealSnMap = make(map[string]int)
	DeviceRealSnMap = new(sync.Map)
}

type JSONS struct {
	//必须的大写开头
	Code int16
	Msg  string
	Data interface{} // 泛型
}
type R_JSONS_List struct {
	//必须的大写开头
	Data      []interface{}
	Num       int64
	Page      int
	Page_size int
}
type R_JSONS struct {
	//必须的大写开头
	Data      interface{}
	Num       int64
	Page      int
	Page_size int
}

type R1_JSONS struct {
	//必须的大写开头
	List      interface{}
	Num       int
	Page      int
	Page_size int
	Pages     []Page_T
}

// 登录验证
//func Verification(GetCookie string, GetString string) (bool, Account.Admin) {
//	Run_My_Server = true // 运行当期服务
//	// 自适应 参数
//	User_tokey := GetCookie
//	if len(User_tokey) == 0 {
//		User_tokey = GetString
//	}
//	if len(User_tokey) == 0 {
//		return false, Account.Admin{}
//	}
//	tokey, is := Account.Redis_Tokey_Get(User_tokey)
//	T_uuid := strings.Split(tokey, "|")[0]
//	if !is {
//		return false, Account.Admin{}
//	}
//	var err error
//	admin_r, err := Account.Read_Admin_ByUuid(T_uuid)
//	if err != nil {
//		return false, Account.Admin{}
//	}
//	Admin_r = &admin_r
//	log.Println("登录 Admin_name 为：", Admin_r.T_name)
//	return true, admin_r
//}

// func_page 分页   [{3 1} {4 2} {4 3} {4 4} {4 5} {4 6} {4 7} {4 8} {4 9} {5 2}]-
type Page_T struct {
	A int
	V int64
}

func Func_page(Page int64, Page_size int64) (page_t_list []Page_T) {
	if Page > 1 {
		page_t_list = append(page_t_list, Page_T{A: 1, V: Page - 1})
	}
	i := int64(0)
	for aa := int64(1); aa < 5; aa++ {
		if Page-aa <= 0 {
			break
		}
		page_t_list = append(page_t_list, Page_T{A: 2, V: Page - aa})
		i++
	}
	page_t_list = append(page_t_list, Page_T{A: 3, V: Page})

	for aa := int64(1); aa < 10-i; aa++ {
		if Page_size < Page+aa {
			break
		}
		page_t_list = append(page_t_list, Page_T{A: 4, V: Page + aa})
	}
	sort.Slice(page_t_list, func(i, j int) bool {
		if page_t_list[i].V < page_t_list[j].V {
			return true
		}
		return false
	})
	sort.Slice(page_t_list, func(i, j int) bool {
		if page_t_list[i].A < page_t_list[j].A {
			return true
		}
		return false

	})
	if Page < Page_size {
		page_t_list = append(page_t_list, Page_T{A: 5, V: Page + 1})
	}

	return page_t_list
}

func Strval(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

func To_int(value interface{}) int {
	var key int
	if value == nil {
		return key
	}
	switch value.(type) {
	case float64:
		key = int(value.(float64))
	case float32:
		key = int(value.(float32))
	case int:
		key = int(value.(int))
	case uint:
		key = int(value.(uint))
	case int8:
		key = int(value.(int8))
	case uint8:
		key = int(value.(uint8))
	case int16:
		key = int(value.(int16))
	case uint16:
		key = int(value.(uint16))
	case int32:
		key = int(value.(int32))
	case uint32:
		key = int(value.(uint32))
	case int64:
		key = int(value.(int64))
	case uint64:
		key = int(value.(uint64))
	case string:
		key, _ = strconv.Atoi(value.(string))
	case []byte:
		key, _ = strconv.Atoi(string(value.([]byte)))
	default:
		newValue, _ := json.Marshal(value)
		key, _ = strconv.Atoi(string(newValue))
	}
	return key
}

func To_float32(value interface{}) float32 {
	var key float32
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		key = float32(value.(float64))
	case float32:
		key = float32(value.(float32))
	case int:
		key = float32(value.(int))
	case uint:
		key = float32(value.(uint))
	case int8:
		key = float32(value.(int8))
	case uint8:
		key = float32(value.(uint8))
	case int16:
		key = float32(value.(int16))
	case uint16:
		key = float32(value.(uint16))
	case int32:
		key = float32(value.(int32))
	case uint32:
		key = float32(value.(uint32))
	case int64:
		key = float32(value.(int64))
	case uint64:
		key = float32(value.(uint64))
	case string:
		key_float64, _ := strconv.ParseFloat(value.(string), 32/64)
		key = float32(key_float64)
	case []byte:
		key_float64, _ := strconv.ParseFloat(string(value.([]byte)), 32/64)
		key = float32(key_float64)
	default:
		newValue, _ := json.Marshal(value)
		key_float64, _ := strconv.ParseFloat(string(newValue), 32/64)
		key = float32(key_float64)
	}

	key_float64, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", key), 32/64)
	key = float32(key_float64)

	return key
}

func To_string(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}
	return key
}

func Float32_to_string(value *float32) string {
	var key string
	if value == nil {
		return key
	}
	return fmt.Sprintf("%.1f", *value)
}

func Random(min, max int) int {
	rand.Seed(time.Now().Unix()) //Seed生成的随机数
	return rand.Intn(max-min) + min
}

// 取文本（字符串）中间
func GetBetweenStr(str, start, end string) string {
	n := strings.Index(str, start)
	if n == -1 {
		n = 0
	} else {
		n = n + len(start) // 增加了else，不加的会把start带上
	}
	str = string([]byte(str)[n:])
	m := strings.Index(str, end)
	if m == -1 {
		m = len(str)
	}
	str = string([]byte(str)[:m])
	return str
}

// getYearMonthToDay 查询指定年份指定月份有多少天
// @params year int 指定年份
// @params month int 指定月份
func GetYearMonthToDay(year int, month int) int {
	// 有31天的月份
	day31 := map[int]bool{
		1:  true,
		3:  true,
		5:  true,
		7:  true,
		8:  true,
		10: true,
		12: true,
	}
	if day31[month] == true {
		return 31
	}
	// 有30天的月份
	day30 := map[int]bool{
		4:  true,
		6:  true,
		9:  true,
		11: true,
	}
	if day30[month] == true {
		return 30
	}
	// 计算是平年还是闰年
	if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
		// 得出2月的天数
		return 29
	}
	// 得出2月的天数
	return 28
}

func Decimal(value float64) float64 {
	value, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", value), 64)
	return value
}

func Strconv_Atoi(string string) int {
	int, _ := strconv.Atoi(string)
	return int
}

// golang获取程序运行路径
func GetCurrentDirectory() string {
	dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))

	return strings.Replace(dir, "\\", "/", -1)
}

// 获取正在运行的函数名
func FuncName() string {
	pc := make([]uintptr, 1)
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	return f.Name()
}

// 获取两个时间相差的天数，0表同一天，正数表t1>t2，负数表t1<t2
func GetDiffDays(t1, t2 time.Time) int {
	t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.Local)
	t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, time.Local)

	return int(t1.Sub(t2).Hours() / 24)
}

func FindStrListMissingData(data1, data2 []string) []string {
	set1 := make(map[string]struct{})
	set2 := make(map[string]struct{})

	for _, item := range data1 {
		set1[item] = struct{}{}
	}

	for _, item := range data2 {
		set2[item] = struct{}{}
	}

	var missing []string
	for item := range set1 {
		if _, found := set2[item]; !found {
			missing = append(missing, item)
		}
	}

	return missing
}

func FindStrListExtraData(data1, data2 []string) []string {
	set1 := make(map[string]struct{})
	set2 := make(map[string]struct{})

	for _, item := range data1 {
		set1[item] = struct{}{}
	}

	for _, item := range data2 {
		set2[item] = struct{}{}
	}

	var extra []string
	for item := range set2 {
		if _, found := set1[item]; !found {
			extra = append(extra, item)
		}
	}

	return extra
}

func StrListEqual(slice1, slice2 []string) bool {
	m := make(map[string]bool)
	for _, v := range slice1 {
		m[v] = true
	}
	for _, v := range slice2 {
		if !m[v] {
			return false
		}
	}
	return true
}
