package controllers

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/sirupsen/logrus"

	"github.com/astaxie/beego"
	validation "github.com/go-ozzo/ozzo-validation/v4"
	"github.com/go-ozzo/ozzo-validation/v4/is"

	"lc/common/models"
	"lc/common/mqtt"
	"lc/common/protocol"
	"lc/common/util"
)

// LampStrategyQueue redis缓存
var LampStrategyQueue = "lamp_strategy_queue" //已修改的灯控编码列表，队列方式，先进先出

var LampHlMqttDown = "hllk/113/lamp/longchi/down"
var LampHlMqttUp = "hllk/113/lamp/longchi/up"

type LampController struct {
	BaseController
}

type ConcentratorInfo struct {
	GID string
	TID int
}

type ReqLampController struct {
	Code         string `json:"code"`         //设备编号，禁止修改
	GID          string `json:"gid"`          //网关ID
	Tenant       string `json:"tenant"`       //租户ID
	Name         string `json:"name"`         //设备名称
	Brand        int    `json:"brand"`        //品牌
	Model        int    `json:"model"`        //型号
	CtlType      int    `json:"ctltype"`      //单灯控制器类型，nb-iot:1,485:2,zigbee:3
	Concentrator string `json:"concentrator"` //集中器编号，zigbee灯控专用，其他类型灯控置空
	Netid        int    `json:"netid"`        //网络号，zigbee灯控专用，其他类型灯控置0
	Channel      int    `json:"channel"`      //通道号，zigbee灯控专用，其他类型灯控置0
	OrgNumber    string `json:"orgnumber"`    //灯编号, zigbee灯控专用，设备上原始的编号，字符串类型
	Strategy     string `json:"strategy"`     //关联的策略编码，无则置空，多个则用逗号分开，暂时只支持一个
	State        int    `json:"state"`        //1启用，0禁用
}

func (a ReqLampController) Validate() error {
	var rules []*validation.FieldRules
	rules = append(rules, validation.Field(&a.Code, validation.Required, validation.Length(4, 32)))
	rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)))
	rules = append(rules, validation.Field(&a.CtlType, validation.Required, validation.In(1, 2, 3, 4)))
	rules = append(rules, validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)))
	rules = append(rules, validation.Field(&a.State, validation.In(0, 1)))
	if a.CtlType == 2 { //485需要网关ID，其他暂不需要
		rules = append(rules, validation.Field(&a.GID, validation.Required, validation.Length(4, 32)))
	} else if a.CtlType == 3 {
		rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
		rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 8)))
	} else if a.CtlType == 4 {
		rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
		rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 32)))
	}
	return validation.ValidateStruct(&a, rules...)
}

type LampControllerDev struct {
	Code         string `json:"code"`         //设备编号，禁止修改
	GID          string `json:"gid"`          //网关ID
	Name         string `json:"name"`         //设备名称
	Brand        int    `json:"brand"`        //品牌
	Model        int    `json:"model"`        //型号
	CtlType      int    `json:"ctltype"`      //单灯控制器类型，nb-iot:1,485:2,zigbee:3
	Concentrator string `json:"concentrator"` //集中器编号，zigbee灯控专用，其他类型灯控置空
	Netid        int    `json:"netid"`        //网络号，zigbee灯控专用，其他类型灯控置0
	Channel      int    `json:"channel"`      //通道号，zigbee灯控专用，其他类型灯控置0
	OrgNumber    string `json:"orgnumber"`    //灯编号, zigbee灯控专用，设备上原始的编号，字符串类型
	Strategy     string `json:"strategy"`     //关联的策略编码，无则置空，多个则用逗号分开，暂时只支持一个
	State        int    `json:"state"`        //1启用，0禁用
}

func (a LampControllerDev) Validate() error {
	var rules []*validation.FieldRules
	rules = append(rules, validation.Field(&a.Code, validation.Required, validation.Length(4, 32)))
	rules = append(rules, validation.Field(&a.CtlType, validation.Required, validation.In(1, 2, 3, 4)))
	rules = append(rules, validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)))
	rules = append(rules, validation.Field(&a.State, validation.In(0, 1)))
	if a.CtlType == 2 { //485需要网关ID，其他暂不需要
		rules = append(rules, validation.Field(&a.GID, validation.Required, validation.Length(4, 32)))
	} else if a.CtlType == 3 {
		rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
		rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 8)))
	} else if a.CtlType == 4 {
		rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
		rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 32)))
	}
	return validation.ValidateStruct(&a, rules...)
}

type ReqImportLampControllerDev struct {
	Tenant string              `json:"tenant"` //租户ID
	List   []LampControllerDev `json:"list"`   //灯控列表
}

func (a ReqImportLampControllerDev) Validate() error {
	var rules []*validation.FieldRules
	rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)))
	rules = append(rules, validation.Field(&a.List, validation.Required))
	return validation.ValidateStruct(&a, rules...)
}

// ReqStrategy 关联策略
type ReqStrategy struct {
	Tenant   string   `json:"tenant"`   //租户ID
	Codes    []string `json:"codes"`    //数组	灯控编码数组
	Strategy string   `json:"strategy"` //	策略编码，无则置空，多个则用逗号分开，暂时只支持一个
}

func (a ReqStrategy) Validate() error {
	return validation.ValidateStruct(&a,
		validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)),
		validation.Field(&a.Codes, validation.Required),
		validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)),
	)
}

// LampStrategy 创建更新策略
type LampStrategy struct {
	Ontime     string `json:"ontime"`     //开始时间，24小时制，格式{小时}:{分钟}:{秒}类似13:06:00，为13点6分
	Offtime    string `json:"offtime"`    //结束时间，24小时制，格式同ontime
	Brightness int    `json:"brightness"` //亮度，1到100
}

func (a LampStrategy) Validate() error {
	return validation.ValidateStruct(&a,
		validation.Field(&a.Ontime, validation.Required, validation.Date("15:04:05")),
		validation.Field(&a.Offtime, validation.Required, validation.Date("15:04:05")),
		validation.Field(&a.Brightness, validation.Min(1), validation.Max(100)),
	)
}

type ReqLampStrategy struct {
	Tenant    string         `json:"tenant"`    //租户ID
	Name      string         `json:"name"`      //策略名称
	Code      string         `json:"code"`      //策略编码，禁止修改
	TimeInfo  []LampStrategy `json:"timeinfo"`  //时间及亮度内容数组，最多4个元素，最少1个元素
	Sunset    int            `json:"sunset"`    //是否启用
	Ctltype   int            `json:"ctltype"`   //单灯控制器类型，nb-iot:1,485:2,zigbee:3 不同灯控可能支持的时间亮度有不同的设置，备用
	Start     string         `json:"start"`     //时间格式，类似2020-07-20 06:06:06
	End       string         `json:"end"`       //时间格式，类似2020-09-20 06:06:06
	Year      int            `json:"year"`      //是否全年，1全年，0非全年
	Auto      int            `json:"auto"`      //1,自动延续，0非自动延续
	Longitude string         `json:"longitude"` //东正西负。双精度浮点数，整数最多3字符，小数最多6字符
	Latitude  string         `json:"latitude"`  //北正南负，双精度浮点数，整数最多2字符，小数最多6字符
}

func (a ReqLampStrategy) Validate() error {
	var rules []*validation.FieldRules
	rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)))
	rules = append(rules, validation.Field(&a.Code, validation.Length(4, 32)))
	rules = append(rules, validation.Field(&a.TimeInfo, validation.Length(1, 4))) //最少1个，最多4个
	rules = append(rules, validation.Field(&a.Sunset, validation.In(0, 1)))
	rules = append(rules, validation.Field(&a.Year, validation.In(0, 1)))
	rules = append(rules, validation.Field(&a.Auto, validation.In(0, 1)))
	//rules = append(rules, validation.Field(&a.Ctltype, validation.Required, validation.In(1, 2, 3)))
	rules = append(rules, validation.Field(&a.Start, validation.Required, validation.Date("2006-01-02 15:04:05")))
	rules = append(rules, validation.Field(&a.End, validation.Required, validation.Date("2006-01-02 15:04:05")))
	rules = append(rules, validation.Field(&a.Longitude, validation.Required, is.Longitude))
	rules = append(rules, validation.Field(&a.Latitude, validation.Required, is.Latitude))
	return validation.ValidateStruct(&a, rules...)
}

// ReqSwitch 开/关灯
type ReqSwitch struct {
	Tenant     string   `json:"tenant"`          //租户ID
	Codes      []string `json:"codes"`           //数组	灯控编码数组，一次开关灯多个
	Recovery   int      `json:"recovery"`        //恢复时间，即开或关灯时长，超过这个时间则自动恢复时控模式
	Brightness int      `json:"brightness"`      //0~100,0相当于关等，100最大亮度
	SwitchOn   int      `json:"switchon"`        //1开灯，0关灯
	Whole      int      `json:"whole,omitempty"` //1为集控
}

func (a ReqSwitch) Validate() error {
	return validation.ValidateStruct(&a,
		validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)),
		validation.Field(&a.Codes, validation.Required),
		validation.Field(&a.Recovery, validation.Required, validation.Min(1), validation.Max(480)),
		validation.Field(&a.Brightness, validation.Min(0), validation.Max(100)),
		validation.Field(&a.SwitchOn, validation.In(0, 1)),
		// validation.Field(&a.Whole, validation.In(0, 1)),
	)
}

// ConvertNumber 长和zigbee单灯控制器编号，短横线连接
func ConvertNumber(strNumber string) uint16 {
	strlist := strings.Split(strNumber, "-")
	if len(strlist) == 2 {
		hight, err0 := strconv.Atoi(strlist[0])
		low, err1 := strconv.Atoi(strlist[1])
		if err0 == nil && err1 == nil {
			return uint16(hight<<8 | low)
		}
	}
	return 0
}

// CreateLampController @Title 创建灯控设备
// @Description 创建灯控设备
// @Param   body body controllers.ReqLampController true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/create [post]
func (o *LampController) CreateLampController() {
	var obj ReqLampController
	if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
		beego.Debug(string(o.Ctx.Input.RequestBody))
		o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
		return
	}
	if err := obj.Validate(); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}
	var number uint16 = 0
	if obj.CtlType == 3 { //长和zigbee集控器
		number = ConvertNumber(obj.OrgNumber)
		if number == 0 {
			beego.Error("请求的编号格式不正确，要求\"xx-xx\"")
			o.Response(Failure, "请求的编号格式不正确，要求\"xx-xx\"", nil)
		}
	}

	oo := models.DeviceLampController{
		ID:      obj.Code, //设备ID，DID
		Name:    obj.Name,
		GID:     obj.GID,     //网关ID
		Brand:   obj.Brand,   //品牌
		Model:   obj.Model,   //型号
		CtlType: obj.CtlType, //单灯控制器类型，nb-iot:1,485:2,zigbee:3

		Concentrator: obj.Concentrator, //集中器编号，zigbee灯控专用，其他类型灯控置空
		Netid:        obj.Netid,        //网络号，zigbee灯控专用，其他类型灯控置0
		Channel:      obj.Channel,      //通道号，zigbee灯控专用，其他类型灯控置0
		Number:       number,           //灯编号, zigbee灯控专用，其他类型灯控置0
		OrgNumber:    obj.OrgNumber,    //灯编号, zigbee灯控专用，设备上原始的编号，字符串类型

		Strategy: obj.Strategy, //关联的策略编码，无则置空，多个则用逗号分开，暂时只支持一个
		Tenant:   obj.Tenant,   //租户ID
		State:    obj.State,    //1启用，0禁用
	}
	//检查是否有网关ID
	if obj.CtlType == 3 || obj.CtlType == 4 { //查找灯控关联的zigbee集中器信息
		if concentrator, err := models.GetConcentratorbyID(obj.Concentrator); err == nil {
			oo.GID = concentrator.GID
			oo.TID = concentrator.TID
		} else {
			beego.Error(fmt.Sprintf("操作失败，请先创建zigbee集控器:%s", err.Error()))
			o.Response(Failure, fmt.Sprintf("操作失败，请先创建zigbee集控器:%s", err.Error()), nil)
			return
		}
	} else if obj.CtlType == 2 {
		oo.TID = 2
	}
	if err := oo.SaveFromWeb(obj.CtlType); err != nil {
		o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil)
		return
	}

	//存入redis，等待下发给设备
	if err := redisCltRawdata.LPush(LampStrategyQueue, obj.Code).Err(); err != nil {
		logrus.Errorf("LampController.CreateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", obj.Code, err.Error())
	}

	o.Response(Success, "成功", oo.ID)
}

// UpdateLampController @Title 更新灯控设备
// @Description 更新灯控设备
// @Param   body body controllers.ReqLampController true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/update [post]
func (o *LampController) UpdateLampController() {
	var obj ReqLampController
	if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
		beego.Debug(string(o.Ctx.Input.RequestBody))
		o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
		return
	}
	if err := obj.Validate(); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}
	var number uint16 = 0
	if obj.CtlType == 3 { //长和zigbee集控器
		number = ConvertNumber(obj.OrgNumber)
		if number == 0 {
			beego.Error("请求的编号格式不正确，要求\"xx-xx\"")
			o.Response(Failure, "请求的编号格式不正确，要求\"xx-xx\"", nil)
		}
	}
	oo := models.DeviceLampController{
		ID:           obj.Code, //设备ID，DID
		Name:         obj.Name,
		GID:          obj.GID,          //网关ID
		Brand:        obj.Brand,        //品牌
		Model:        obj.Model,        //型号
		CtlType:      obj.CtlType,      //单灯控制器类型，nb-iot:1,485:2,zigbee:3
		Concentrator: obj.Concentrator, //集中器编号，zigbee灯控专用，其他类型灯控置空
		Netid:        obj.Netid,        //网络号，zigbee灯控专用，其他类型灯控置0
		Channel:      obj.Channel,      //通道号，zigbee灯控专用，其他类型灯控置0
		Number:       number,           //灯编号, zigbee灯控专用，其他类型灯控置0
		OrgNumber:    obj.OrgNumber,    //灯编号, zigbee灯控专用，设备上原始的编号，字符串类型
		Strategy:     obj.Strategy,     //关联的策略编码，无则置空，多个则用逗号分开，暂时只支持一个
		Tenant:       obj.Tenant,       //租户ID
		State:        obj.State,        //1启用，0禁用
	}
	//检查是否有网关ID
	if obj.CtlType == 3 { //查找灯控关联的zigbee集中器信息
		if concentrator, err := models.GetConcentratorbyID(obj.Concentrator); err == nil {
			oo.GID = concentrator.GID
			oo.TID = concentrator.TID
		} else {
			beego.Error(fmt.Sprintf("操作失败，请先创建zigbee集控器:%s", err.Error()))
			o.Response(Failure, fmt.Sprintf("操作失败，请先创建zigbee集控器:%s", err.Error()), nil)
			return
		}
	} else if obj.CtlType == 2 {
		oo.TID = 2
	}
	if err := oo.SaveFromWeb(obj.CtlType); err != nil {
		o.Response(Failure, fmt.Sprintf("数据更新失败:%s", err.Error()), nil)
		return
	}

	//存入redis，等待下发给设备
	if err := redisCltRawdata.LPush(LampStrategyQueue, obj.Code).Err(); err != nil {
		logrus.Errorf("LampController.UpdateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", obj.Code, err.Error())
	}

	o.Response(Success, "成功", oo.ID)
}

// DeleteLampController @Title 删除灯控设备
// @Description 删除灯控设备
// @Param   code    query   string     true "设备ID"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/delete [post]
func (o *LampController) DeleteLampController() {
	code := strings.Trim(o.GetString("code"), " ")
	if err := validation.Validate(code, validation.Required, validation.Length(4, 100)); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}

	c := models.DeviceLampController{
		ID: code,
	}
	if err := c.Delete(); err != nil {
		beego.Error(fmt.Sprintf("删除失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("数据删除失败:%s", err.Error()), nil)
		return
	}
	o.Response(Success, "成功", c.ID)
}

// UpdateState @Title 更新灯控设备启用禁用状态
// @Description 更新灯控设备启用禁用状态
// @Param   body controllers.ProgramsState true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/update/state [POST]
func (o *LampController) UpdateState() {
	code := o.GetString("code")
	state, err := o.GetUint8("state", 0)
	if code == "" || state > 1 || err != nil {
		beego.Error("参数错误")
		o.Response(Failure, "参数错误", nil)
		return
	}
	err = models.LampControllerUpdateState(code, int(state))
	if err != nil {
		beego.Error("更新灯控设备状态错误:", err.Error())
		o.Response(Failure, "失败", err.Error())
		return
	}
	o.Response(Success, "成功", code)
}

// ImportLampControllerDev @Title 导入灯控设备
// @Description 导入灯控设备
// @Param   body body controllers.ReqImportLampControllerDev true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/import [post]
func (o *LampController) ImportLampControllerDev() {
	var obj ReqImportLampControllerDev
	if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
		beego.Debug(string(o.Ctx.Input.RequestBody))
		o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
		return
	}
	if err := obj.Validate(); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}
	var resp []RespImport
	mapConcentratorInfo := make(map[string]*ConcentratorInfo)
	for _, v := range obj.List {
		var aresp RespImport
		aresp.Code = v.Code
		var number uint16 = 0
		if v.CtlType == 3 { //长和zigbee集控器
			number = ConvertNumber(v.OrgNumber)
		}
		oo := models.DeviceLampController{
			ID:           v.Code, //设备ID，DID
			Name:         v.Name,
			GID:          v.GID,          //网关ID
			Brand:        v.Brand,        //品牌
			Model:        v.Model,        //型号
			CtlType:      v.CtlType,      //单灯控制器类型，nb-iot:1,485:2,zigbee:3
			Concentrator: v.Concentrator, //集中器编号，zigbee灯控专用，其他类型灯控置空
			Netid:        v.Netid,        //网络号，zigbee灯控专用，其他类型灯控置0
			Channel:      v.Channel,      //通道号，zigbee灯控专用，其他类型灯控置0
			Number:       number,         //灯编号, zigbee灯控专用，其他类型灯控置0
			OrgNumber:    v.OrgNumber,    //灯编号, zigbee灯控专用，设备上原始的编号，字符串类型
			Strategy:     v.Strategy,     //关联的策略编码，无则置空，多个则用逗号分开，暂时只支持一个
			Tenant:       obj.Tenant,     //租户ID
			State:        v.State,        //1启用，0禁用
		}
		//检查是否有网关ID
		if v.CtlType == 3 { //查找灯控关联的zigbee集中器信息
			if ci, ok := mapConcentratorInfo[v.Concentrator]; ok {
				oo.GID = ci.GID
				oo.TID = ci.TID
			} else {
				if concentrator, err := models.GetConcentratorbyID(v.Concentrator); err == nil {
					oo.GID = concentrator.GID
					oo.TID = concentrator.TID
					mapConcentratorInfo[v.Concentrator] = &ConcentratorInfo{GID: concentrator.GID, TID: concentrator.TID}
				} else {
					beego.Error(fmt.Sprintf("操作失败，请先创建zigbee集控器:%s", err.Error()))
					aresp.Error = err.Error()
					continue
				}
			}
		} else if v.CtlType == 2 {
			oo.TID = 2
		}
		err := oo.SaveFromWeb(v.CtlType)
		if err != nil {
			beego.Error(fmt.Sprintf("zigbee集控器数据导入失败,code=%s,失败原因:%s", v.Code, err.Error()))
			aresp.Error = err.Error()
			continue
		}
		//存入redis，等待下发给设备
		if err := redisCltRawdata.LPush(LampStrategyQueue, v.Code).Err(); err != nil {
			logrus.Errorf("LampController.CreateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", v.Code, err.Error())
		}
	}
	o.Response(Success, "成功", resp)
}

// RelateStrategy @Title 关联策略
// @Description 关联策略
// @Param   body controllers.ReqStrategy true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/relate/strategy [post]
func (o *LampController) RelateStrategy() {
	var obj ReqStrategy
	if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
		beego.Debug(string(o.Ctx.Input.RequestBody))
		o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
		return
	}
	if err := obj.Validate(); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}
	if err := models.UpdateStrategy(obj.Codes, obj.Strategy); err != nil {
		beego.Error(fmt.Sprintf("关联策略失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("关联策略失败:%s", err.Error()), nil)
		return
	}

	//存入redis，等待下发给设备
	if len(obj.Codes) > 0 {
		codelist := make([]interface{}, 0, len(obj.Codes))
		for _, v := range obj.Codes {
			codelist = append(codelist, v)
		}
		if err := redisCltRawdata.LPush(LampStrategyQueue, codelist...).Err(); err != nil {
			logrus.Errorf("LampController.RelateStrategy:创建灯控缓存redis失败,灯控编码:%v,失败原因:%s", codelist, err.Error())
		}
	}

	o.Response(Success, "成功", nil)
}

// CreateStrategy @Title 创建灯控策略
// @Description 创建灯控策略
// @Param   body controllers.ReqLampStrategy true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/create/strategy [post]
func (o *LampController) CreateStrategy() {
	var obj ReqLampStrategy
	if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
		beego.Debug(string(o.Ctx.Input.RequestBody))
		o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
		return
	}

	if err := obj.Validate(); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}

	tstart, err1 := util.MlParseTime(obj.Start)
	tend, err2 := util.MlParseTime(obj.End)
	if err1 != nil || err2 != nil || tstart.After(tend) {
		o.Response(Failure, "有效期时间错误", nil)
		return
	}
	timeInfo, _ := json.MarshalIndent(&obj.TimeInfo, "", " ")
	longitude, _ := strconv.ParseFloat(obj.Longitude, 64)
	latitude, _ := strconv.ParseFloat(obj.Latitude, 64)
	oo := models.Lampstrategy{
		ID:        obj.Code,
		Name:      obj.Name,
		CtlType:   obj.Ctltype,
		TimeInfo:  string(timeInfo),
		Sunset:    obj.Sunset,
		Start:     tstart,
		End:       tend,
		Year:      obj.Year,
		Auto:      obj.Auto,
		Tenant:    obj.Tenant,
		Longitude: longitude,
		Latitude:  latitude,
	}
	if err := oo.SaveFromWeb(); err != nil {
		o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil)
		return
	}
	o.Response(Success, "成功", obj.Code)
}

// UpdateStrategy @Title 更新灯控策略
// @Description 更新灯控策略
// @Param   body controllers.ReqLampStrategy true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/update/strategy [post]
func (o *LampController) UpdateStrategy() {
	o.Response(Failure, "不允许更改照明策略，可新建照明策略，并关联新策略", nil)
	/*	var obj ReqLampStrategy
		if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
			beego.Debug(string(o.Ctx.Input.RequestBody))
			o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
			return
		}
		if err := obj.Validate(); err != nil {
			beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
			o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
			return
		}
		tstart, err1 := util.MlParseTime(obj.Start)
		tend, err2 := util.MlParseTime(obj.End)
		if err1 != nil || err2 != nil || tstart.After(tend) {
			o.Response(Failure, "有效期时间错误", nil)
			return
		}
		time_info, _ := json.MarshalIndent(&obj.TimeInfo, "", " ")
		longitude, _ := strconv.ParseFloat(obj.Longitude, 64)
		latitude, _ := strconv.ParseFloat(obj.Latitude, 64)
		oo := models.Lampstrategy{
			ID:        obj.Code,
			Name:      obj.Name,
			CtlType:   obj.Ctltype,
			TimeInfo:  string(time_info),
			Sunset:    obj.Sunset,
			Start:     tstart,
			End:       tend,
			Year:      obj.Year,
			Auto:      obj.Auto,
			Tenant:    obj.Tenant,
			Longitude: longitude,
			Latitude:  latitude,
		}

		if err := oo.SaveFromWeb(); err != nil {
			o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil)
			return
		}
		o.Response(Success, "成功", obj.Code)
	*/
}

// DeleteStrategy @Title 删除灯控策略
// @Description 删除灯控策略
// @Param   code    query   string     true "设备ID"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/delete/strategy [post]
func (o *LampController) DeleteStrategy() {
	code := strings.Trim(o.GetString("code"), " ")
	if err := validation.Validate(code, validation.Required, validation.Length(4, 100)); err != nil {
		beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
		o.Response(Failure, err.Error(), nil)
		return
	}
	c := models.Lampstrategy{
		ID: code,
	}
	if err := models.G_db.Delete(c).Error; err != nil {
		beego.Error(fmt.Sprintf("删除失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("数据删除失败:%s", err.Error()), nil)
		return
	}
	o.Response(Success, "成功", c.ID)
}

// Switch @Title 开灯/关灯
// @Description 开灯/关灯
// @Param   body controllers.ReqSwitch true "数据"
// @Success 0 {int} BaseResponse.Code "成功"
// @Failure 1 {int} BaseResponse.Code "失败"
// @router /v1/switch [post]
func (o *LampController) Switch() {
	var obj ReqSwitch
	if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
		beego.Debug(string(o.Ctx.Input.RequestBody))
		o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
		return
	}

	if err := obj.Validate(); err != nil {
		beego.Error(fmt.Sprintf("LampController.Switch:请求参数验证失败:%s", err.Error()))
		o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
		return
	}

	arr, err := models.GetLampControllerByID(obj.Codes)
	if err != nil {
		o.Response(Failure, err.Error(), nil)
		return
	}

	//处理zigbee单灯控制器
	var mapConcentrator = make(map[string][]uint32)
	var mapConcentratorGateway = make(map[string]string)
	for _, v := range arr {
		if v.CtlType == 3 && v.Concentrator != "" && v.Number > 0 { //长和zigbee
			mapConcentrator[v.Concentrator] = append(mapConcentrator[v.Concentrator], uint32(v.Number)) //集控器
			mapConcentratorGateway[v.Concentrator] = v.GID                                              //网关
		}
	}
	for k, v := range mapConcentrator {
		seq := GetNextUint64()
		var sw protocol.Pack_CHZB_Switch
		str, err := sw.EnCode(k, mapConcentratorGateway[k], seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), v)
		if err != nil {
			beego.Error(fmt.Sprintf("LampController.Switch:编码错误:%s", err.Error()))
			continue
		}
		topic := GetTopic(obj.Tenant, protocol.DT_CONCENTRATOR, k, protocol.TP_CHZB_SET_SWITCH)
		err = GetMqttHandler().PublishString(topic, str, mqtt.AtLeastOnce)
		if err != nil {
			beego.Error(fmt.Sprintf("LampController.Switch:消息发布错误:%s", err.Error()))
			continue
		}
		//进入指令表
		var msg string
		if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
			msg = string(msg0)
		} else {
			msg = str
		}
		dcr := models.DeviceCmdRecord{
			ID:      seq,
			GID:     mapConcentratorGateway[k],
			DID:     k, //集控器编号
			Topic:   topic,
			State:   0,
			Message: msg,
		}
		if err := models.G_db.Create(&dcr).Error; err != nil {
			logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
		}
	}

	//处理裕明485单灯控制器
	for _, v := range arr {
		if v.CtlType == 2 {
			seq := GetNextUint64()
			var sw protocol.Pack_CHZB_Switch
			str, err := sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil)
			if err != nil {
				beego.Error(fmt.Sprintf("LampController.Switch:编码错误:%s", err.Error()))
				continue
			}
			topic := GetTopic(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH)
			err = GetMqttHandler().PublishString(topic, str, mqtt.AtLeastOnce)
			if err != nil {
				beego.Error(fmt.Sprintf("LampController.Switch:消息发布错误:%s", err.Error()))
				continue
			}
			//进入指令表
			var msg string
			if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
				msg = string(msg0)
			} else {
				msg = str
			}
			dcr := models.DeviceCmdRecord{
				ID:      seq,
				GID:     v.GID,
				DID:     v.ID,
				Topic:   topic,
				State:   0,
				Message: msg,
			}
			if err := models.G_db.Create(&dcr).Error; err != nil {
				logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
			}
		}
	}

	//海蓝zigbee单灯控制器
	for _, v := range arr {
		if v.CtlType == 4 {

			// seq := GetNextUint64()
			seq := uint64(util.MlNow().Unix())
			var str string
			var err error
			if obj.Whole == 0 { //集控器开关
				var sw protocol.HLWLZB_Switch
				str, err = sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil)
				if err != nil {
					beego.Error(fmt.Sprintf("HLWLLampController.Switch:编码错误:%s", err.Error()))
					continue
				}
				beego.Debug(fmt.Sprintf("HLWLLampController.Switch:%s", str))
				topic := GethltopicDown(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH)
				err = GetMqttHandlerHL().PublishString(topic, str, mqtt.AtLeastOnce)
				if err != nil {
					beego.Error(fmt.Sprintf("HLWLLampController.Switch:消息发布错误:%s", err.Error()))
					continue
				}
				//进入指令表
				var msg string
				if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
					msg = string(msg0)
				} else {
					msg = str
				}
				dcr := models.DeviceCmdRecord{
					ID:      seq,
					GID:     v.GID,
					DID:     v.ID,
					Topic:   topic,
					State:   0,
					Message: msg,
				}
				if err := models.G_db.Create(&dcr).Error; err != nil {
					logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
				}
			} else { //普通开关
				var sw protocol.HLWLZB_Whole_Switch
				str, err = sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil)
				if err != nil {
					beego.Error(fmt.Sprintf("HLWLLampController.Switch:编码错误:%s", err.Error()))
					continue
				}
				beego.Debug(fmt.Sprintf("HLWLLampController.Switch:%s", str))
				topic := GethltopicDown(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH)
				err = GetMqttHandlerHL().PublishString(topic, str, mqtt.AtLeastOnce)
				if err != nil {
					beego.Error(fmt.Sprintf("HLWLLampController.Switch:消息发布错误:%s", err.Error()))
					continue
				}
				//进入指令表
				var msg string
				if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
					msg = string(msg0)
				} else {
					msg = str
				}
				dcr := models.DeviceCmdRecord{
					ID:      seq,
					GID:     v.GID,
					DID:     v.ID,
					Topic:   topic,
					State:   0,
					Message: msg,
				}
				if err := models.G_db.Create(&dcr).Error; err != nil {
					logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
				}
			}

		}
	}

	var lsrs []models.LampSwitchRecord
	tt := util.MlNow()
	ttend := tt.Add(time.Duration(obj.Recovery) * time.Minute)
	for _, v := range obj.Codes {
		lsr := models.LampSwitchRecord{
			DID:        v,
			SwitchOn:   uint8(obj.SwitchOn),
			Duration:   uint(obj.Recovery * 60),
			Brightness: uint8(obj.Brightness),
			TStart:     tt,
			TEnd:       ttend,
			CreatedAt:  util.MlNow(),
		}
		lsrs = append(lsrs, lsr)
	}
	if err := models.MultiInsertLampSwitchRecord(lsrs); err != nil {
		beego.Error("LampController.Switch:批量插入开关灯记录错误:", err.Error())
	}
	o.Response(Success, "成功", nil)
}

// GetTopic 下发的控制命令
//topic格式：{tenant}/{GID}/{did}/{TP}
//func GetCtrlTopic(tenant, gid, did, tp string) string {
//	return tenant + "/" + gid + "/" + did + "/" + tp
//}
func GetTopic(tenant, devtype, id, topic string) string {
	return tenant + "/" + devtype + "/" + id + "/" + topic
}

// GethltopicDown 下发的控制命令先固定,再从配置文件读
//topic格式：hllk/113/lamp/longchi/down
func GethltopicDown(tenant, devtype, id, topic string) string {
	return "hllk/113/lamp/longchi/down"
}
