package zigbee

import (
	"encoding/binary"
	"errors"
	"time"

	"github.com/valyala/bytebufferpool"
)

var (
	HeadFlag2Down uint8 = 0xF2
	HeadFlag2Up   uint8 = 0xF3
)

var (
	CmdSendData    uint8 = 0x0B
	CmdSendDataAck uint8 = 0x8B
	CmdSetPid      uint8 = 0x13
	CmdGetPid      uint8 = 0x14
	CmdSetPidAck   uint8 = 0x93
	CmdGetPidAck   uint8 = 0x94
)

var ErrorProtocol = errors.New("协议错误")
var ErrorInvalidCrc1 = errors.New("外层CRC校验错误")
var ErrorInvalidCrc2 = errors.New("内层CRC校验错误")

type Pack interface {
	SetData(Count, No, Cmd uint16, Data []byte)
	EnCode() (*bytebufferpool.ByteBuffer, error)
	DeCode(Data []byte) error
}

// MsgHeader2 消息格式
type MsgHeader2 struct {
	Head    byte   //集中到单灯F2，单灯到集中F3
	PoleID  uint32 //杆号
	Cmd2    uint8  //固定为F2
	Seq     uint8  //流水号，循环利用
	Length2 uint8  //包体2长度
	Body2   Pack   //包体内容,普通功能协议或升级功能协议
	Crc2    uint16 //内层CRC
}

func (o *MsgHeader2) SetDody(body Pack) {
	o.Body2 = body
}

func (o *MsgHeader2) SetData(PoleID uint32, Seq uint8) {
	o.PoleID = PoleID
	o.Seq = Seq
}

func (o *MsgHeader2) EnCode() (*bytebufferpool.ByteBuffer, error) {
	bytebuf, err := o.Body2.EnCode() //Body2   Pack   //包体内容,普通功能协议或升级功能协议
	defer func() {
		if bytebuf != nil {
			bytebufferpool.Put(bytebuf)
		}
	}()
	if err != nil {
		return nil, err
	}
	buff := bytebufferpool.Get()
	buff.WriteByte(HeadFlag2Down) //Head    byte   //集中到单灯F2，单灯到集中F3
	tmp := make([]byte, 4)
	binary.BigEndian.PutUint32(tmp, o.PoleID)
	buff.Write(tmp)                      //LampID  uint32 //杆号
	buff.WriteByte(0xF2)                 //Cmd2    uint8  //固定为F2
	buff.WriteByte(o.Seq)                //Seq     uint8  //流水号，循环利用
	buff.WriteByte(uint8(bytebuf.Len())) //Length2 uint8  //包体2长度
	buff.Write(bytebuf.B)                //Body2   Pack   //包体内容,普通功能协议或升级功能协议

	crc16 := CRC16(buff.B)
	tmp2 := make([]byte, 2)
	binary.BigEndian.PutUint16(tmp2, crc16)
	buff.Write(tmp2) //计算内层CRC16
	return buff, nil
}
func (o *MsgHeader2) DeCode(Data []byte) error {
	if len(Data) >= 10 {
		o.Head = Data[0]                              //集中到单灯F2，单灯到集中F3
		o.PoleID = binary.BigEndian.Uint32(Data[1:5]) //杆号
		o.Cmd2 = Data[5]                              //固定为F2
		o.Seq = Data[6]                               //流水号，循环利用
		o.Length2 = Data[7]                           //包体2长度
		o.Crc2 = binary.BigEndian.Uint16(Data[o.Length2+8 : o.Length2+10])
		crc := CRC16(Data[0 : o.Length2+8])
		if crc != o.Crc2 {
			return ErrorInvalidCrc2
		}
		return o.Body2.DeCode(Data[8 : o.Length2+8])
	}
	return ErrorProtocol
}

// GeneralFunc 普通功能协议
type GeneralFunc struct {
	Len   uint8  //此包长度
	Count uint8  //总包数
	No    uint8  //当前升级包号
	Cmd   uint8  //单杆命令
	Data  []byte //数据内容
}

func (o *GeneralFunc) SetData(Count, No, Cmd uint16, Data []byte) {
	o.Cmd = uint8(Cmd)
	o.Data = Data
	o.Count = uint8(Count)
	o.No = uint8(No)
}
func (o *GeneralFunc) EnCode() (*bytebufferpool.ByteBuffer, error) {
	buff := bytebufferpool.Get()
	buff.WriteByte(uint8(4 + len(o.Data))) // Len   uint8  //此包长度
	buff.WriteByte(0)                      //Count uint8  //总包数
	buff.WriteByte(0)                      //No    uint8  //当前升级包号
	buff.WriteByte(o.Cmd)                  //M1Cmd   uint8  //单杆命令
	buff.Write(o.Data)                     //mapData  []byte //数据内容
	return buff, nil
}
func (o *GeneralFunc) DeCode(Data []byte) error {
	if len(Data) >= 4 {
		o.Len = Data[0]
		o.Count = Data[1]
		o.No = Data[2]
		o.Cmd = Data[3]
		o.Data = Data[4:]
		return nil
	}
	return ErrorProtocol
}

// UpgradeFunc 升级功能协议
type UpgradeFunc struct {
	Len   uint8  //此包长度
	Count uint16 //总包数
	No    uint16 //当前升级包号
	Cmd   uint8  //单杆命令
	Data  []byte //数据内容
}

func (o *UpgradeFunc) SetData(Count, No, Cmd uint16, Data []byte) {
	o.Cmd = uint8(Cmd)
	o.Data = Data
	o.Count = Count
	o.No = No
}
func (o *UpgradeFunc) EnCode() (*bytebufferpool.ByteBuffer, error) {
	buff := bytebufferpool.Get()
	buff.WriteByte(uint8(6 + len(o.Data))) // Len   uint8  //此包长度
	tmp := make([]byte, 2)
	binary.BigEndian.PutUint16(tmp, o.Count)
	buff.Write(tmp) //Count uint16  //总包数
	binary.BigEndian.PutUint16(tmp, o.No)
	buff.Write(tmp)       //No    uint16  //当前升级包号
	buff.WriteByte(o.Cmd) //M1Cmd   uint8  //单杆命令
	buff.Write(o.Data)    //mapData  []byte //数据内容
	return buff, nil
}
func (o *UpgradeFunc) DeCode(Data []byte) error {
	if len(Data) >= 4 {
		o.Len = Data[0]
		o.Count = binary.BigEndian.Uint16(Data[1:3])
		o.No = binary.BigEndian.Uint16(Data[3:5])
		o.Cmd = Data[5]
		o.Data = Data[6:]
		return nil
	}
	return ErrorProtocol
}

type OnOffTime struct {
	OnHour     uint8 `json:"onhour"`
	OnMinite   uint8 `json:"onminite"`
	OffHour    uint8 `json:"offhour"`
	OffMinite  uint8 `json:"offminite"`
	Brightness uint8 `json:"brightness"` //亮度0~100
}

func (o *OnOffTime) SetData(onHour, onMinite, offHour, offMinite, brightness uint8) {
	o.OnHour = onHour
	o.OnMinite = onMinite
	o.OffHour = offHour
	o.OffMinite = offMinite
	o.Brightness = brightness
}

func (o *OnOffTime) EnCode() []byte {
	buff := make([]byte, 5)
	buff[0] = o.OnHour
	buff[1] = o.OnMinite
	buff[2] = o.OffHour
	buff[3] = o.OffMinite
	buff[4] = o.Brightness
	return buff
}
func (o *OnOffTime) DeCode(data []byte) error {
	if len(data) >= 5 {
		o.OnHour = data[0]
		o.OnMinite = data[1]
		o.OffHour = data[2]
		o.OffMinite = data[3]
		o.Brightness = data[4]
		return nil
	}
	return ErrorProtocol
}

func (o *OnOffTime) InTimeRange(t time.Time) bool {
	h := uint8(t.Hour())
	m := uint8(t.Minute())

	if o.OnHour > o.OffHour { //跨日情况,例如19:30~5:30，开灯时间大于关灯时间
		if h > o.OnHour || h < o.OffHour || (h == o.OnHour && m >= o.OnMinite) ||
			(h == o.OffHour && m <= o.OffMinite) {
			return true
		}
	} else if o.OnHour < o.OffHour { //开灯时间小于关灯时间
		if (h > o.OnHour && h < o.OffHour) ||
			(h == o.OnHour && m >= o.OnMinite) ||
			(h == o.OffHour && m <= o.OffMinite) {
			return true
		}
	} else { //开灯时间等于关灯时间
		if h == o.OnHour && m >= o.OnMinite && m <= o.OffMinite {
			return true
		}
	}
	return false
}

// CalculateChddjkZigbeeResponselength 长和单灯控制器zigbee协议，预估长度，非精确长度
func CalculateChddjkZigbeeResponselength(adu []byte) int {
	return int(float32(len(adu)) * 1.5)
}
