package util

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/bwmarrin/snowflake"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"math/rand"
	"net"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

// CheckErr 检查错误
func CheckErr(err error) {
	if err != nil {
		panic(err)
	}
}

// CheckRedisErr 检查redis的错误
func CheckRedisErr(err error) {
	if err != nil && err != redis.Nil {
		panic(err)
	}
}

// SliceToMapString 将字符串的切片转化为map
func SliceToMapString(s []string) map[string]struct{} {
	m := make(map[string]struct{})
	for _, v := range s {
		m[v] = struct{}{}
	}
	return m
}

// EncodeMD5 md5加密
func EncodeMD5(value string) string {
	m := md5.New()
	m.Write([]byte(value))

	return hex.EncodeToString(m.Sum(nil))
}

// GenRandStr 生成随机字符串
func GenRandStr(n int) string {
	str := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	totalNumber := len(str)

	var token = strings.Builder{}
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < n; i++ {
		position := rand.Intn(totalNumber)
		token.WriteByte(str[position])
	}
	return token.String()
}

// IsMobile 判断是否是手机号码
func IsMobile(phone string) bool {
	if m, _ := regexp.MatchString(`^1[0-9]{10}$`, phone); !m {
		return false
	}
	return true
}

// GetNowFormat 返回格式化后的当前日期
func GetNowFormat(format string) string {
	switch format {
	case "Ymd":
		return time.Now().Format("20060102")
	case "Y-m-d":
		return time.Now().Format("2006-01-02")
	default:
		return time.Now().Format("2006-01-02 15:04:06")
	}
}

// GenSmsCode 生成短信验证码
func GenSmsCode() string {
	return fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
}

// GetNowInt 获取今天的日期(年月日整型)
func GetNowInt() (today int) {
	dateStr := GetNowFormat("Ymd")
	today, _ = strconv.Atoi(dateStr)
	return
}

// QuoteConversion 将双引号转化为单引号
func QuoteConversion(msg string) string {
	return strings.Replace(msg, "\"", "'", -1)
}

// F2I float转int类型
func F2I(f float64) int {
	i, _ := strconv.Atoi(fmt.Sprintf("%1.0f", f))
	return i
}

// Struct2Map 结构体转为map
func Struct2Map(obj interface{}) map[string]interface{} {
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)

	var data = make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		data[string(t.Field(i).Tag.Get("json"))] = v.Field(i).Interface()
	}
	return data
}

// GetMapStrKeys 获取map的string key
func GetMapStrKeys(m map[string]interface{}) []string {
	keys := make([]string, 0, len(m))
	for k, _ := range m {
		keys = append(keys, k)
	}
	return keys
}

// GenSignMD5 生成md5签名
func GenSignMD5(m map[string]interface{}, secret string) string {
	keys := GetMapStrKeys(m)
	//排序
	sort.Strings(keys)
	//拼接成字符串
	tmpStr := ""
	for _, v := range keys {
		if v == "sign" {
			continue
		}
		tmpStr += fmt.Sprintf("%s=%v&", v, m[v])
	}
	tmpStr = strings.TrimRight(tmpStr, "&")
	tmpStr += secret
	//md5加密
	return EncodeMD5(tmpStr)
}

// Uint64Random 生成uint64的随机数
func Uint64Random(va11, val2 uint64) uint64 {
	node, _ := snowflake.NewNode(1)
	id := node.Generate().Int64()
	return uint64(id)
}

// GetToday 获取今天的开始与结束时间戳
func GetToday() (int64, int64) {
	currentTime := time.Now()
	startTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location())
	endTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 23, 59, 59, 0, currentTime.Location())
	return startTime.Unix(), endTime.Unix()
}

// IsOpenId 判断是否是openid
func IsOpenId(openid string) bool {
	if m, _ := regexp.MatchString(`^[_A-Za-z0-9\-]{1,40}$`, openid); !m {
		return false
	}
	return true
}

// IsAppId 判断是否是appid
func IsAppId(appid string) bool {
	if m, _ := regexp.MatchString(`^wx[_A-Za-z0-9\-]{10,20}$`, appid); !m {
		return false
	}
	return true
}

// GetRealIp 获取真实的ip
func GetRealIp(r *gin.Context) string {
	ip, _, err := net.SplitHostPort(r.Request.RemoteAddr)
	if err != nil {
		ip = r.Request.RemoteAddr
	}
	if ip != "127.0.0.1" {
		return ip
	}
	// Check if behide nginx or apache
	xRealIP := r.Request.Header.Get("X-Real-Ip")
	xForwardedFor := r.Request.Header.Get("X-Forwarded-For")

	for _, address := range strings.Split(xForwardedFor, ",") {
		address = strings.TrimSpace(address)
		if address != "" {
			return address
		}
	}

	if xRealIP != "" {
		return xRealIP
	}
	return ip
}

// Days 计算开始时间戳与结束时间戳的间隔多少天
func Days(timestampFrom, timestampTo int64) int {
	var midnightUnix = func(t time.Time) int64 {
		y, m, d := t.Date()
		return time.Date(y, m, d+1, 0, 0, 0, 0, time.Local).Unix()
	}

	var days = 0
	for {
		if midnightUnix(time.Unix(timestampFrom, 0).AddDate(0, 0, days)) >= timestampTo {
			days++
			break
		}
		days++
	}
	return days
}

// ParseJsonStr 公共解析json字符串
// jsonStr 字符串
// bind 需要绑定的对象(业务逻辑中要使用的话则传递指针结构体)
func ParseJsonStr(jsonStr string, bind interface{}) error {
	return json.Unmarshal([]byte(jsonStr), &bind)
}
