package utils

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"math/rand"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/astaxie/beego"
)

func TimeSub(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 MarkBackUrl(backUrl, defaultUrl string) string {
	if len(backUrl) == 0 {
		backUrl = defaultUrl
	} else {
		backURLByte, err := base64.URLEncoding.DecodeString(backUrl)
		if err != nil {
			backUrl = backUrl
		} else {
			backUrl = string(backURLByte)
		}
	}
	return backUrl
}

func CheckMobile(mobile string) (match bool) {

	//过滤手机
	match, _ = regexp.MatchString("^1\\d{10}$", mobile)
	return
}

func RandCode(min, max int64) string {
	if min >= max || min == 0 || max == 0 {
		return strconv.FormatInt(max, 10)
	}
	rand.Seed(time.Now().UnixNano())
	randNum := rand.Int63n(max-min) + min
	return strconv.FormatInt(randNum, 10)
}

func TimeAgo(timeUnix int64) string {
	timeUnixS := time.Unix(timeUnix, 0)
	timeNow := time.Now()
	timeSub := timeNow.Sub(timeUnixS)

	if timeSub < time.Minute*1 {
		return "刚刚"
	} else if timeSub < time.Hour*1 {
		return strconv.Itoa(int(timeSub.Minutes())) + "分钟前"
	} else if timeSub < time.Hour*24 {
		return strconv.Itoa(int(timeSub.Hours())) + "小时前"
	} else if timeSub < time.Hour*24*7 {
		return strconv.Itoa(int(timeSub.Hours()/24)) + "天前"
	} else {
		return timeUnixS.Format("2006-01-02 15:04")
	}
	return ""
}

//Signature sha1签名
func Signature(params ...string) string {
	sort.Strings(params)
	h := sha1.New()
	for _, s := range params {
		io.WriteString(h, s)
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}

//RandomStr 随机生成字符串
func RandomStr(length int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

//GetCurrTs return current timestamps
func GetCurrTs() int64 {
	return time.Now().Unix()
}

func SetThisRequestURI(uri string) string {
	return fmt.Sprintf("%v%v", beego.AppConfig.String("httpdomain"), uri)
}

func SetThisBasr64RequestURI(uri string) string {
	backUrl := fmt.Sprintf("%v%v", beego.AppConfig.String("httpdomain"), uri)
	backUrl = base64.URLEncoding.EncodeToString([]byte(backUrl))

	return backUrl
}

func TransNum2Str(read int64) (transRead string) {
	if read < 0 {
		transRead = "0"
	} else if read < 10000 {
		transRead = fmt.Sprintf("%v", read)
	} else {
		var c float64 = 10000
		var rc float64 = float64(read)
		transRead = fmt.Sprintf("%.2f万", rc/c)
	}

	return
}

func GenMobileToken(mobile string) (token string) {
	st := strings.Split(mobile, "")

	s := fmt.Sprintf("%s%v%v%v%v%v%v", mobile, st[0], st[1], st[3], st[7], st[6], st[9])

	h := sha1.New()
	h.Write([]byte(s))
	bs := h.Sum(nil)

	token = fmt.Sprintf("%x", bs)

	return
}

func CheckMobileToken(mobile, token string) bool {
	o := GenMobileToken(mobile)
	if token == o {
		return true
	}

	return false
}

type jSapiConfig struct {
	AppID     string `json:"app_id"`
	Timestamp int64  `json:"timestamp"`
	NonceStr  string `json:"nonce_str"`
	Signature string `json:"signature"`
}

//GetAJTConfig jsapi_ticket config
func GetAJTConfig(jsapiTicket, uri string) (jSapiConfig, error) {
	var config jSapiConfig
	nonceStr := RandomStr(16)
	timestamp := GetCurrTs()
	str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", jsapiTicket, nonceStr, timestamp, uri)
	sigStr := Signature(str)

	config.AppID = beego.AppConfig.String("wxappId")
	config.NonceStr = nonceStr
	config.Timestamp = timestamp
	config.Signature = sigStr
	return config, nil
}

func TrimHtml(src string) string {
	//将HTML标签全转换成小写
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	src = re.ReplaceAllStringFunc(src, strings.ToLower)
	//去除STYLE
	re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
	src = re.ReplaceAllString(src, "")
	//去除SCRIPT
	re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
	src = re.ReplaceAllString(src, "")
	//去除所有尖括号内的HTML代码，并换成换行符
	re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
	src = re.ReplaceAllString(src, "\n")
	//去除连续的换行符
	re, _ = regexp.Compile("\\s{2,}")
	src = re.ReplaceAllString(src, "\n")
	return strings.TrimSpace(src)
}

func SubString(str string, begin, length int) string {
	rs := []rune(str)
	lth := len(rs)
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length

	if end > lth {
		end = lth
	}
	return string(rs[begin:end])
}

func ParseTimeStringToTime(layout string, timeStr string) (*time.Time, error) {
	if len(layout) == 0 || len(timeStr) == 0 {
		return nil, errors.New("layout 或 日期字符串 为空，无法解析")
	}
	loc, _ := time.LoadLocation("Local")
	date, parseDateErr := time.ParseInLocation(layout, timeStr, loc)
	return &date, parseDateErr
}

// 获取 date 所在周的周一和周日，以周一0点为一周的开始，周日24点为一周的结束
func GetMondayAndSundayOfWeekDate(date *time.Time) (time.Time, time.Time) {
	if date == nil {
		now := time.Now()
		date = &now
	}
	weekday := int(date.Weekday())
	if weekday == 0 {
		weekday = 7
	}
	loc, _ := time.LoadLocation("Local")
	monday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 1-weekday).Format("2006-01-02")+" 00:00:00", loc)
	sunday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 7-weekday).Format("2006-01-02")+" 23:59:59", loc)
	return monday, sunday
}

func GetMondayAndSundayOfNextWeekDate(date *time.Time) (time.Time, time.Time) {
	if date == nil {
		now := time.Now()
		date = &now
	}
	weekday := int(date.Weekday())
	if weekday == 0 {
		weekday = 7
	}
	loc, _ := time.LoadLocation("Local")
	monday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 8-weekday).Format("2006-01-02")+" 00:00:00", loc)
	sunday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 14-weekday).Format("2006-01-02")+" 23:59:59", loc)
	return monday, sunday
}

func GetMondayAndSundayOfNextNextWeekDate(date *time.Time) (time.Time, time.Time) {
	if date == nil {
		now := time.Now()
		date = &now
	}
	weekday := int(date.Weekday())
	if weekday == 0 {
		weekday = 7
	}
	loc, _ := time.LoadLocation("Local")
	monday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 15-weekday).Format("2006-01-02")+" 00:00:00", loc)
	sunday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 21-weekday).Format("2006-01-02")+" 23:59:59", loc)
	return monday, sunday
}
