package controllers

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"math/rand"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/astaxie/beego"
	jsoniter "github.com/json-iterator/go"

	"lc/common/util"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary
var IDGen util.IdWorker

var ErrorUserPassword = errors.New("用户名密码错误")
var ErrorDataUnvalid = errors.New("数据错误")

var (
	Success = 0
	Failure = 1
)

type RedisConfig struct {
	Conn     string `json:"conn"`
	Password string `json:"password"`
}

// FileDownloadInfo 素材下载
type FileDownloadInfo struct {
	ID        uint
	SourceUrl string
	SavaPath  string
}

var DownQueue *util.MlQueue

var bjtz *time.Location
var LcFiledir string
var FileBaseUrl string
var BaseUrl string

func init() {
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		bjtz = time.Local
	} else {
		bjtz = loc
	}

	IDGen.InitIdWorker(1000, 1)

	DownQueue = util.NewQueue(10000)

	//LcFiledir, _ = filepath.Abs(filepath.Dir(os.Args[0]))
	LcFiledir, _ = os.Getwd()
	LcFiledir = LcFiledir + string(filepath.Separator) + "file" + string(filepath.Separator)
	BaseUrl = beego.AppConfig.String("baseurl")
	FileBaseUrl = BaseUrl + "/file/"

	if GetMqttHandler() == nil {
		panic("GetMqttHandler错误")
	}

	go GetEventMgr().Handler()
	//go DownloadFile()
}

func GetNextUint64() uint64 {
	u64, _ := IDGen.NextId()
	return uint64(u64)
}

const (
	KcRandKindNum   = 0 // 纯数字
	KcRandKindLower = 1 // 小写字母
	KcRandKindUpper = 2 // 大写字母
	KcRandKindAll   = 3 // 数字、大小写字母
)

// Krand 随机字符串
func Krand(size int, kind int) []byte {
	ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
	isAll := kind > 2 || kind < 0
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < size; i++ {
		if isAll {
			ikind = rand.Intn(3)
		}
		scope, base := kinds[ikind][0], kinds[ikind][1]
		result[i] = uint8(base + rand.Intn(scope))
	}
	return result
}

type BaseController struct {
	beego.Controller
	UserName string
	Password string
}

type BaseResponse struct {
	Code    int         `json:"code"`
	Message string      `json:"msg"`
	Data    interface{} `json:"data,omitempty"`
}

func LcValidation(user string, password string) (uint, string, error) {
	list, err := redisCltRawdata.HMGet(user, "id", "code", "password").Result()
	if err != nil {
		beego.Error("LcValidation发生错误:", err)
		return 0, "", err
	} else {
		if list[0] == nil || list[1] == nil || list[2] == nil {
			beego.Error("LcValidation从redis返回的数据不完整:", list)
			return 0, "", ErrorDataUnvalid
		}

		if list[2].(string) != password {
			beego.Error("用户名密码错误,用户名:", user, ",密码:", password)
			return 0, "", ErrorUserPassword
		}

		id, err := strconv.Atoi(list[0].(string))
		if err != nil {
			beego.Error("LcValidation发生ID转换错误:", list[0].(string))
			return 0, "", err
		}
		//if err := redisCltRawdata.HSet(LED_STATUS_PREFIX+list[0].(string), TIME, util.MlNow().Format("2006-01-02 15:04:05")).Err(); err != nil {
		//	beego.Error("CheckLogin缓存时间发生错误:", err)
		//}
		return uint(id), list[1].(string), nil
	}
}

func (c *BaseController) Prepare() {
	username, password, ok := c.Ctx.Request.BasicAuth()
	if ok {
		c.UserName = username
		c.Password = password
	}
}

func (c *BaseController) Response(Code int, Message string, Data interface{}) {
	var respObj BaseResponse
	respObj.Code = Code
	respObj.Message = Message
	respObj.Data = Data
	c.Data["json"] = respObj
	c.ServeJSON()
}

type ErrorController struct {
	beego.Controller
}

func (o *ErrorController) Error404() {
	var obj BaseResponse
	obj.Code = 404
	obj.Message = "资源不存在,请检查URL"
	obj.Data = "Resouce Not Found"
	o.Data["json"] = obj
	o.ServeJSON()
}

func (o *ErrorController) Error501() {
	var obj BaseResponse
	obj.Code = 501
	obj.Message = "API内部错误，请联系管理员"
	obj.Data = "Server Error"
	o.Data["json"] = obj
	o.ServeJSON()
}

func GetDeviceSubId(gwid string, comid int, rtuid string) string {
	id := gwid + "_" + strconv.Itoa(comid) + "_" + rtuid
	return id
}

func CheckMD5(reader io.Reader, strmd5 string) bool {
	if strmd5 == "" {
		return true
	}
	md5hash := md5.New()
	_, err := io.Copy(md5hash, reader)
	if err != nil {
		return true
	}
	strmd5_ := strings.ToLower(hex.EncodeToString(md5hash.Sum(nil)))
	if strmd5 != strmd5_ {
		return false
	}
	return true
}

func GetRelationids(js string) string {
	reg := regexp.MustCompile(`dat\w{16,}`)
	s := reg.FindAllString(js, -1)
	if len(s) > 0 {
		if len(s) > 1 {
			sort.Strings(s)
			ss := Duplicate(s)
			return strings.Replace(strings.Trim(fmt.Sprint(ss), "[]"), " ", ";", -1)
		} else {
			return s[0]
		}
	}
	return ""
}

func Duplicate(a interface{}) (ret []interface{}) {
	va := reflect.ValueOf(a)
	for i := 0; i < va.Len(); i++ {
		if i > 0 && reflect.DeepEqual(va.Index(i-1).Interface(), va.Index(i).Interface()) {
			continue
		}
		ret = append(ret, va.Index(i).Interface())
	}
	return ret
}
