package services

import (
	"github.com/gogf/gf/encoding/gjson"
	"math/rand"
	"sparrow/pkg/models"
	"sparrow/pkg/rpcs"
	"sparrow/pkg/scene"
	"sparrow/pkg/server"
	"sparrow/services/knowoapi/model"
)

// DeviceService device service接口
type DeviceService interface {
	// 获取厂商已经激活的设备总数
	GetDeviceCount(vendorid string) (int, error)
	//返回厂商某天激活的设备数
	GetActiveNumberOfDate(vendor string, datetime string) (int, error)
	//获取厂商某天活跃的设备数
	GetLivelyCountOfDate(string, string) (int, error)
	//获取近N日激活设备数据
	GetActiveOfNumDays(string, int) ([]map[string]interface{}, error)
	//获取近N日活跃设备数据
	GetLivelyOfNumDays(string, int) ([]map[string]interface{}, error)
	//获取已经激活的设备列表
	GetDevices(vendorid, proid string, pi, ps int, deviceid string) ([]*models.Devices, int, error)
	//获取用户下所有设备的数量，在线设备的数量，离线设备的数量
	GetDevicesCountByVenderId(vendorid string) (map[string]interface{}, error)
	// Update 更新设备信息
	Update(Device *models.Device) error
	// Upgrade 发起设备OTA升级
	Upgrade(params *models.UpgradeParams) error
	// GetUpgradeProgress 获取ota升级进度
	GetUpgradeProgress(deviceId string) (rpcs.ReplyOtaProgress, error)
	// GetDeviceStatus 获取设备状态数据
	GetDeviceStatus(deviceId, productId string) (*gjson.Json, error)
	// GetDeviceEvent 获取设备事件信息
	GetDeviceEvent(deviceId, productId string) (*gjson.Json, error)
	// SetReport 获取设备状态
	SetReport(params models.SendSplitCommandParams) (*gjson.Json, error)
	// Restart 重启设备
	Restart(params models.SendSplitCommandParams) error
	// ClearData 清除设备配置数据
	ClearData(params models.SendSplitCommandParams) error
	// SetDataTrans 设备端自动上报配置
	SetDataTrans(params models.SendSplitCommandParams) error
	// GetInfo 获取网关信息
	GetInfo(params models.SendSplitCommandParams) (*gjson.Json, error)
	// ForceRun 远程控制某个模块强制运行
	ForceRun(params models.SendSplitCommandParams) error
	// SetDeviceId 写入设备id
	SetDeviceId(params models.SendSplitCommandParams) error
	// SetFjsqStatus 智能分集水器控制
	SetFjsqStatus(params models.SendSplitCommandParams) error
	// SetOutdoorPower 设置水系统外机电源状态
	SetOutdoorPower(params models.SendSplitCommandParams) error
	// SetOutdoorTemp 设置水系统外机出水温度
	SetOutdoorTemp(params models.SendSplitCommandParams) error
	// SetOutdoorLinkage 开启/关闭水系统联动
	SetOutdoorLinkage(params models.SendSplitCommandParams) error
	// SetMixedWaterLinkage 开启/关闭调温中心联动
	SetMixedWaterLinkage(params models.SendSplitCommandParams) error
	// SendCommand 下发指令
	SendCommand(args rpcs.ArgsSendCommand) error
	// GetScenes 获取场景
	GetScenes(code string, pi, ps int) ([]*scene.InfoScene, int, error)
}

type deviceservice struct {
	models *model.All
}

// NewDeviceService create device manager
func NewDeviceService(models *model.All) DeviceService {
	return deviceservice{
		models: models,
	}
}

func (a deviceservice) Update(Device *models.Device) error {
	_, err := a.models.Device.Update(Device)
	return err
}

func (a deviceservice) GetDevices(vendorid, proid string, pi, ps int, deviceid string) ([]*models.Devices, int, error) {

	data, total, err := a.models.Device.GetDevices(vendorid, proid, pi, ps, deviceid)

	if err != nil {
		return nil, 0, err
	}

	dataMap := make([]*models.Devices, 0)

	for _, device := range data {

		onlineargs := rpcs.ArgsGetDeviceOnlineStatus{
			Id: device.DeviceIdentifier,
		}

		onlinereply := rpcs.ReplyGetDeviceOnlineStatus{}
		err = server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetDeviceOnlineStatus", onlineargs, &onlinereply)
		if err != nil && err.Error() != "redigo: nil returned" {
			server.Log.Errorf("get devie online status error: %v", err)

			return nil, 0, err
		}

		devices := new(models.Devices)

		devices.Device = device

		if int(onlinereply.HeartbeatInterval) > 0 && len(onlinereply.ClientIP) > 0 {
			devices.Status = 1
		}

		dataMap = append(dataMap, devices)
	}

	return dataMap, total, nil
}
func (a deviceservice) GetDeviceCount(vendorid string) (int, error) {
	return a.models.Device.GetDeviceCount(vendorid)
}
func (a deviceservice) GetActiveNumberOfDate(vendorid string, datetime string) (int, error) {
	return a.models.Device.GetActiveNumberOfDate(vendorid, datetime)
}
func (a deviceservice) GetLivelyCountOfDate(vendorid string, datetime string) (int, error) {
	return a.models.Device.GetLivelyCountOfDate(vendorid, datetime)
}
func (a deviceservice) GetActiveOfNumDays(vendorid string, days int) ([]map[string]interface{}, error) {
	return a.models.Device.GetActiveOfNumDays(vendorid, days)
}
func (a deviceservice) GetLivelyOfNumDays(vendorid string, days int) ([]map[string]interface{}, error) {
	return a.models.Device.GetLivelyOfNumDays(vendorid, days)
}
func (a deviceservice) GetDevicesCountByVenderId(vendorid string) (map[string]interface{}, error) {
	data, err := a.models.Device.GetDevicesByVenderId(vendorid)

	if err != nil {
		return nil, err
	}

	var onlineCount int

	var offlineCount int
	for _, device := range data {
		onlineargs := rpcs.ArgsGetDeviceOnlineStatus{
			Id: device.DeviceIdentifier,
		}
		onlinereply := rpcs.ReplyGetDeviceOnlineStatus{}
		err = server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetDeviceOnlineStatus", onlineargs, &onlinereply)
		if err != nil && err.Error() != "redigo: nil returned" {
			server.Log.Errorf("get devie online status error: %v", err)
			return nil, err
		}

		if int(onlinereply.HeartbeatInterval) > 0 && len(onlinereply.ClientIP) > 0 {
			onlineCount += 1
		} else {
			offlineCount += 1
		}
	}

	deviceCount := map[string]interface{}{
		"TotalData":    len(data),
		"OnlineCount":  onlineCount,
		"OfflineCount": offlineCount,
	}

	return deviceCount, nil
}

func (a deviceservice) Upgrade(params *models.UpgradeParams) error {
	var fileArgs rpcs.ArgsOtaFile
	fileArgs.FileData = params.File
	fileArgs.FileId = rand.Intn(9000) + 1000
	var reply rpcs.ReplyEmptyResult

	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.SavaFile", fileArgs, &reply)
	if err != nil {
		server.Log.Errorf("OTA升级文件保存失败：%v", err)
		return err
	}
	var args rpcs.ArgsSendCommand
	args.Cmd = string(models.OtaUpgrade)
	args.DeviceId = params.DeviceID
	args.Params = map[string]interface{}{
		"fileId":   fileArgs.FileId,
		"fileSize": params.FileSize,
	}
	err = a.sendCommand(args)
	if err != nil {
		return err
	}

	server.Log.Debugf("ota升级请求成功")
	return nil
}

func (a deviceservice) GetUpgradeProgress(deviceId string) (rpcs.ReplyOtaProgress, error) {
	var args rpcs.ArgsOtaProgress
	args.DeviceId = deviceId

	var reply rpcs.ReplyOtaProgress

	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetProgress", args, &reply)
	if err != nil {
		server.Log.Errorf("OTA升级进度获取失败：%v", err)
		return reply, err
	}
	server.Log.Debugf("获取升级进度请求成功")
	return reply, nil
}

func (a deviceservice) GetDeviceStatus(deviceId, productId string) (*gjson.Json, error) {
	var args rpcs.ArgsGetStatus
	args.Id = deviceId
	args.ProductId = productId
	var reply rpcs.ReplyStatus

	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetDeviceStatus", args, &reply)
	if err != nil {
		server.Log.Errorf("设备状态数据获取失败：%v", err)
		return nil, err
	}
	return gjson.New(reply.Status), nil
}

func (a deviceservice) GetDeviceEvent(deviceId, productId string) (*gjson.Json, error) {
	var args rpcs.ArgsGetStatus
	args.Id = deviceId
	args.ProductId = productId
	var reply rpcs.ReplayEvent

	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetDeviceEvent", args, &reply)
	if err != nil {
		server.Log.Errorf("设备事件数据获取失败：%v", err)
		return nil, err
	}
	return gjson.New(reply.Event), nil
}

// SetReport 获取设备状态
func (a deviceservice) SetReport(params models.SendSplitCommandParams) (*gjson.Json, error) {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.Report)
	err := a.sendCommand(args)
	if err != nil {
		return nil, err
	}
	return a.GetDeviceStatus(params.DeviceId, params.ProductId)
}

// Restart 重启设备
func (a deviceservice) Restart(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.Restart)
	return a.sendCommand(args)
}

// ClearData 清除设备配置数据
func (a deviceservice) ClearData(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.ClearData)
	return a.sendCommand(args)
}

// SetDataTrans 设备端自动上报配置
func (a deviceservice) SetDataTrans(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Params = map[string]interface{}{
		"enable":   params.Enable,
		"internal": params.Internal,
	}
	args.Cmd = string(models.SetDataTrans)
	return a.sendCommand(args)
}

// GetInfo 获取网关信息
func (a deviceservice) GetInfo(params models.SendSplitCommandParams) (*gjson.Json, error) {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.GetInfo)
	err := a.sendCommand(args)
	if err != nil {
		return nil, err
	}

	var newArgs rpcs.ArgsGetStatus
	newArgs.Id = params.DeviceId
	newArgs.ProductId = params.ProductId
	var reply rpcs.ReplayInfo

	err = server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetDeviceInfo", newArgs, &reply)
	if err != nil {
		server.Log.Errorf("设备状态数据获取失败：%v", err)
		return nil, err
	}
	return gjson.New(reply.Info), nil
}

// ForceRun 远程控制某个模块强制运行
func (a deviceservice) ForceRun(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.ForceRun)
	args.Params = map[string]interface{}{
		"module": params.Module,
		"power":  params.ModulePower,
	}
	return a.sendCommand(args)
}

// SetDeviceId 写入设备id
func (a deviceservice) SetDeviceId(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.SetDeviceId)
	args.Params = map[string]interface{}{
		"id":     params.Id,
		"prefix": params.Prefix,
	}
	return a.sendCommand(args)
}

// SetFjsqStatus 智能分集水器控制
func (a deviceservice) SetFjsqStatus(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.SetFjsqStatus)
	args.Params = map[string]interface{}{
		"num":   params.Num,
		"power": params.NumPower,
	}
	return a.sendCommand(args)
}

// SetOutdoorPower 设置水系统外机电源状态
func (a deviceservice) SetOutdoorPower(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.SetOutdoorPower)
	args.Params = map[string]interface{}{
		"power": params.OutdoorPower,
	}
	return a.sendCommand(args)
}

// SetOutdoorTemp 设置水系统外机出水温度
func (a deviceservice) SetOutdoorTemp(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.SetOutdoorTemp)
	args.Params = map[string]interface{}{
		"cool_mode_temp": params.CoolModeTemp,
		"heat_mode_temp": params.HeatModeTemp,
	}
	return a.sendCommand(args)
}

// SetOutdoorLinkage 开启/关闭水系统联动
func (a deviceservice) SetOutdoorLinkage(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.SetOutdoorTemp)
	args.Params = map[string]interface{}{
		"enable": params.Enable,
	}
	return a.sendCommand(args)
}

// SetMixedWaterLinkage 开启/关闭调温中心联动
func (a deviceservice) SetMixedWaterLinkage(params models.SendSplitCommandParams) error {
	var args rpcs.ArgsSendCommand
	args.DeviceId = params.DeviceId
	args.Cmd = string(models.SetOutdoorTemp)
	args.Params = map[string]interface{}{
		"enable": params.Enable,
	}
	return a.sendCommand(args)
}

// SendCommand 下发指令
func (a deviceservice) sendCommand(args rpcs.ArgsSendCommand) error {
	var reply rpcs.ReplySendCommand
	err := server.RPCCallByName(nil, rpcs.ControllerName, "Controller.SendCommand", args, &reply)
	if err != nil {
		server.Log.Errorf("指令下发失败：%v", err)
		return err
	}
	return nil
}

// SendCommand 下发指令
func (a deviceservice) SendCommand(args rpcs.ArgsSendCommand) error {
	var reply rpcs.ReplySendCommand
	err := server.RPCCallByName(nil, rpcs.ControllerName, "Controller.SendCommand", args, &reply)
	if err != nil {
		server.Log.Errorf("指令下发失败：%v", err)
		return err
	}
	return nil
}

// GetScenes 获取场景
func (a deviceservice) GetScenes(code string, pi, ps int) ([]*scene.InfoScene, int, error) {
	var args rpcs.ArgsGetAllScene
	args.Code = code
	args.Pi = pi
	args.Ps = ps
	var reply rpcs.ReplyScenes
	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetAllScenesPage", args, &reply)
	if err != nil {
		server.Log.Errorf("设备状态数据获取失败：%v", err)
		return nil, 0, err
	}
	return reply.Result, reply.Total, nil
}
