package admin

import (
	"encoding/json"
	"errors"
	"fmt"
	"regexp"
	"runtime"
	"server/dao"
	"server/model/common"
	"server/utils/logger"
	"server/utils/mqtt"
	"server/utils/protocol"
	"strings"
	"sync"
	"time"
)

func InitMqtt() {
	MqttService = GetHandler()
	MqttService.SubscribeTopics()
	go MqttService.Handler()
}

var MqttService *MqttHandler

var timeoutReg = regexp.MustCompile("Client .* has exceeded timeout")
var connectReg = regexp.MustCompile(`New client connected from .* as .*\(`)
var disconnectReg = regexp.MustCompile("Client mqttx_893e4b7d disconnected")

type MqttHandler struct {
	queue *mqtt.MlQueue
}

var _handlerOnce sync.Once
var _handlerSingle *MqttHandler

func GetHandler() *MqttHandler {
	_handlerOnce.Do(func() {
		_handlerSingle = &MqttHandler{
			queue: mqtt.NewQueue(10000),
		}
	})
	return _handlerSingle
}

func (o *MqttHandler) SubscribeTopics() {
	mqtt.GetMQTTMgr().Subscribe("smart_tunnel/#", mqtt.AtLeastOnce, o.HandlerData)
}

func (o *MqttHandler) HandlerData(m mqtt.Message) {
	for {
		ok, cnt := o.queue.Put(&m)
		if ok {
			break
		} else {
			logger.Get().Error("HandlerData:查询队列失败,队列消息数量:%d", cnt)
			runtime.Gosched()
		}
	}
}

func (o *MqttHandler) Handler() interface{} {
	defer func() {
		if err := recover(); err != nil {
			go GetHandler().Handler()
			//logger.Logger.Errorf("MqttHandler.Handler:发生异常:%s", string(debug.Stack()))
		}
	}()
	for {
		msg, ok, quantity := o.queue.Get()
		if !ok {
			time.Sleep(10 * time.Millisecond)
			continue
		} else if quantity > 1000 {
			logger.Get().Warnf("数据队列累积过多,请注意优化,当前队列条数:%d", quantity)
		}
		m, ok := msg.(*mqtt.Message)
		if !ok {
			continue
		}

		sn, operate, err := ParseTopic(m.Topic())
		if err != nil {
			//logger.Logger.Errorf("parseTopic err")
			continue
		}

		switch operate {
		case protocol.TopicGatherDataEnv:
			var data dao.EnvData
			if err := json.Unmarshal(m.Payload(), &data); err != nil {
				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
				continue
			}
			data.TunnelSn = sn
			if data.Sn == "" {
				continue
			}
			err = data.CreateEnvData()
			if err != nil {
				logger.Get().Errorf("sn：%s device：%s 新增环境信息失败: %v", sn, data.Sn, err)
				continue
			}
		case protocol.TopicGatherDataOpt:
			var data dao.OpticalData
			if err := json.Unmarshal(m.Payload(), &data); err != nil {
				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
				continue
			}
			data.TunnelSn = sn
			if data.Sn == "" {
				continue
			}
			err = data.CreateOpticalData()
			if err != nil {
				logger.Get().Errorf("sn：%s device：%s 新增光感信息失败: %v", sn, data.Sn, err)
				continue
			}
		case protocol.TopicGatherDataDG:
			var data common.InductanceData
			if err := json.Unmarshal(m.Payload(), &data); err != nil {
				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
				continue
			}
			dao.InductanceDetails{
				DeviceSn:         data.Sn,
				TotalActivePower: data.TotalPower,
				UploadTime:       time.Now().Format("2006-01-02 15:04:05"),
			}.CreateInductanceDetails()
		case protocol.TopicSwitchStates:
			var data common.SwitchData
			if err := json.Unmarshal(m.Payload(), &data); err != nil {
				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
				continue
			}
			if data.TurnOf == 1 {
				dao.UpdateRelayState(data.Sn, data.Way, true)
			} else {
				dao.UpdateRelayState(data.Sn, data.Way, false)
			}

		case protocol.TopicLampBrightNess:
			var data common.LampData
			if err := json.Unmarshal(m.Payload(), &data); err != nil {
				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
				continue
			}
			if data.Way == 1 {
				dao.UpdateTunnelLamp1(sn, data.BrightNess)
			} else {
				dao.UpdateTunnelLamp2(sn, data.BrightNess)
			}
		}

	}
}

func (o *MqttHandler) Publish(topic string, data interface{}) error {
	return mqtt.GetMQTTMgr().Publish(topic, data, mqtt.AtLeastOnce)
}

func (o *MqttHandler) GetTopic(sn, protocol string) string {
	return fmt.Sprintf("smart_tunnel/%s/%s", sn, protocol)
}

// ParseTopic 获取设备SN, topic
// "mini/*****/switch_control/ack"
func ParseTopic(topic string) (sn string, operate string, err error) {
	strList := strings.Split(topic, "/")
	sn = strList[1]
	operate = strList[2]
	if len(strList) != 3 {
		return "", "", errors.New("不支持的topic")
	}
	return
}
