package device

import (
	"errors"
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cast"
	"strings"
	"sync"
	"time"
)

var (
	EWSTypeRaw = "raw"
)

type Esp8266WifiSwitch struct {
	sync.Mutex

	brand    string
	model    string
	deviceId string
	client   mqtt.Client
	callback Callback
}

func NewEsp8266WifiSwitch(deviceId string, mqttClient mqtt.Client, callback Callback) *Esp8266WifiSwitch {
	u := &Esp8266WifiSwitch{
		client:   mqttClient,
		deviceId: deviceId,
		callback: callback,
		brand:    BrandESP8266,
		model:    "wsp8",
	}

	if callback != nil {
		var token mqtt.Token = nil
		if deviceId == "#" {
			token = mqttClient.Subscribe(fmt.Sprintf("%s/%s/%s", u.brand, u.model, deviceId), 2, u.Callback)
		} else {
			token = mqttClient.Subscribe(fmt.Sprintf("%s/%s/%s/#", u.brand, u.model, deviceId), 2, u.Callback)
		}
		if err := token.Error(); err != nil {
			log.Errorf("[%s:%s] device[%s] Subscribe error:%s", u.brand, u.model, deviceId, err.Error())
		}
	}
	return u
}

func (u *Esp8266WifiSwitch) TurnOn(idx int) error {
	if u.deviceId == "#" {
		return nil
	}
	topic := fmt.Sprintf("%s/%s/%s/cmd", u.brand, u.model, u.deviceId)
	publishACK := u.client.Publish(topic, 0, false, fmt.Sprintf("a%d", idx+1))
	publishACK.WaitTimeout(time.Second)
	return publishACK.Error()
}

func (u *Esp8266WifiSwitch) TurnOff(idx int) error {
	if u.deviceId == "#" {
		return nil
	}
	topic := fmt.Sprintf("%s/%s/%s/cmd", u.brand, u.model, u.deviceId)
	publishACK := u.client.Publish(topic, 0, false, fmt.Sprintf("c%d", idx+1))
	publishACK.WaitTimeout(time.Second)
	return publishACK.Error()
}

func (u *Esp8266WifiSwitch) KeepAlive() error {
	if u.deviceId == "#" {
		return nil
	}
	topic := fmt.Sprintf("%s/%s/%s/cmd", u.brand, u.model, u.deviceId)
	publishACK := u.client.Publish(topic, 0, false, "qa") //查询继电器状态
	publishACK.WaitTimeout(time.Second)
	return publishACK.Error()
}

func (u *Esp8266WifiSwitch) Operate(cmd string) error {
	if u.deviceId == "#" {
		return errors.New("不支持的操作#")
	}
	topic := fmt.Sprintf("%s/%s/%s/cmd", u.brand, u.model, u.deviceId)
	publishACK := u.client.Publish(topic, 0, false, cmd) //查询继电器状态
	publishACK.WaitTimeout(time.Second)
	return publishACK.Error()
}

func (u *Esp8266WifiSwitch) Callback(client mqtt.Client, message mqtt.Message) {
	u.Lock()
	defer u.Unlock()

	topic := message.Topic()
	payload := message.Payload()

	// res的才回调,忽略cmd请求
	if !strings.HasSuffix(topic, "res") {
		return
	}

	log.Debugf("[%s][%s] deviceId[%s] topic[%s] payloyad[%s]", u.brand, u.model, u.deviceId, topic, string(payload))

	var callMsg Message
	callMsg.MsgType = EWSTypeRaw
	callMsg.MsgTime = time.Now().Unix()
	callMsg.MsgId = cast.ToString(message.MessageID())
	callMsg.DeviceId = u.getDeviceId(topic)
	callMsg.Topic = topic

	callMsg.Data = make(map[string]interface{})
	callMsg.Data["raw"] = string(payload)
	u.callback(&callMsg)
}

func (u *Esp8266WifiSwitch) getDeviceId(topic string) string {
	devId := u.deviceId
	if devId == "#" {
		fields := strings.Split(topic, "/")
		if len(fields) >= 2 {
			devId = fields[2]
		}
	}

	return devId
}