package com.njcn.energy.handler;

import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.github.tocrhz.mqtt.annotation.MqttSubscribe;
import com.github.tocrhz.mqtt.annotation.NamedValue;
import com.github.tocrhz.mqtt.annotation.Payload;
import com.github.tocrhz.mqtt.publisher.MqttPublisher;
import com.njcn.energy.pojo.constant.ApiParam;
import com.njcn.energy.pojo.dto.DeviceOperateDTO;
import com.njcn.energy.pojo.dto.RegisterDTO;
import com.njcn.energy.pojo.enums.EnergyResponseEnum;
import com.njcn.energy.pojo.po.EleLogs;
import com.njcn.energy.service.IEleLogsService;
import com.njcn.energy.service.IModelService;
import com.njcn.redis.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Objects;

/**
 * @author hongawen
 * @version 1.0.0
 * @date 2022年03月23日 09:41
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MqttMessageHandler {

    private final MqttPublisher publisher;

    private final IModelService modelService;

    private final RedisUtil redisUtil;

    private final IEleLogsService eleLogsService;


    /**
     * 设备注册
     */
    @MqttSubscribe(value = "/device/register",qos = 1)
    public void register(String topic, MqttMessage message, @Payload String payload) {
        String result = modelService.deviceRegister(new String(message.getPayload(), StandardCharsets.UTF_8));
        publisher.send("/platform/register",result,1,false);
        EleLogs eleLogs = new EleLogs();
        eleLogs.setType(1);
        //设备取消注册，需要通知平台
        Gson gson = new Gson();
        RegisterDTO.RegisterRequest registerDTO = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), RegisterDTO.RegisterRequest.class);
        RegisterDTO.RegisterResponse response = gson.fromJson(result, RegisterDTO.RegisterResponse.class);
        if (registerDTO.getParam().getType() == 0){
            eleLogs.setType(0);
            if (response.getCode() == 200 && response.getParam().getRes() == 1){
                DeviceOperateDTO deviceOperateDTO = new DeviceOperateDTO();
                deviceOperateDTO.setNdid(registerDTO.getParam().getNDid());
                deviceOperateDTO.setDid(response.getParam().getDid());
                deviceOperateDTO.setTime(Long.toString(System.currentTimeMillis()/1000));
                deviceOperateDTO.setMessage("装置取消注册");
                deviceOperateDTO.setType("003");
                publisher.send("/device/platform",gson.toJson(deviceOperateDTO),1,false);
            }
        }
        //将日志存库
        eleLogs.setNdid(registerDTO.getParam().getNDid());
        eleLogs.setReqTime(LocalDateTime.ofEpochSecond(Long.parseLong(registerDTO.getTimestamp()), 0, ZoneOffset.ofHours(8)));
        eleLogs.setInfo(response.getMsg());
        eleLogs.setCreateTime(LocalDateTime.now());
        eleLogsService.addLogs(eleLogs);
    }

    /**
     * 设备接入
     */
    @MqttSubscribe(value = "/device/pltreq/{version}/{edgeId}",qos = 1)
    public void access(String topic, MqttMessage message, @NamedValue("edgeId") String edgeId,@NamedValue("version") String version, @Payload String payload) throws InterruptedException {
        String result = modelService.deviceAccess(new String(message.getPayload(), StandardCharsets.UTF_8),edgeId);
        Gson gson = new Gson();
        RegisterDTO.RegisterRequest registerDTO = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), RegisterDTO.RegisterRequest.class);
        RegisterDTO.RegisterResponse response = gson.fromJson(result, RegisterDTO.RegisterResponse.class);
        //设备接入成功，需要通知平台
        if (response.getCode() == 200 && Objects.equals(response.getType(), ApiParam.REP_LINKUP)){
            DeviceOperateDTO deviceOperateDTO = new DeviceOperateDTO();
            deviceOperateDTO.setNdid(edgeId);
            deviceOperateDTO.setDid(registerDTO.getParam().getDid());
            deviceOperateDTO.setTime(Long.toString(System.currentTimeMillis()/1000));
            deviceOperateDTO.setMessage("装置上线");
            deviceOperateDTO.setType("004");
            publisher.send("/device/platform",gson.toJson(deviceOperateDTO),1,false);
            deviceOperateDTO.setMessage("主题更新");
            deviceOperateDTO.setType("002");
            publisher.send("/device/operate",gson.toJson(deviceOperateDTO),1,false);
        }
        //有装置异常需要主动下线，需要通知平台
        if (response.getCode() == 300 && Objects.equals(response.getType(), ApiParam.REP_HEARTBEAT)){
            DeviceOperateDTO deviceOperateDTO = new DeviceOperateDTO();
            deviceOperateDTO.setNdid(edgeId);
            deviceOperateDTO.setDid(registerDTO.getParam().getDid());
            deviceOperateDTO.setTime(Long.toString(System.currentTimeMillis()/1000));
            deviceOperateDTO.setMessage("装置下线");
            deviceOperateDTO.setType("005");
            publisher.send("/device/platform",gson.toJson(deviceOperateDTO),1,false);
            response.setCode(Integer.parseInt(EnergyResponseEnum.SUCCESS.getCode()));
            result = gson.toJson(response);
        }
        /**
         *  如果心跳超过3分钟，下线当前网关所有装置，需要通知平台，记录数据库掉线时间
         *  使用redis的过期时间做处理
         */
        redisUtil.saveByKeyWithExpire("MQTT:" + edgeId,registerDTO.getTimestamp(),180L);
        redisUtil.saveByKeyWithExpire(edgeId,registerDTO.getTimestamp(),200L);
        //将日志存库
        if (!Objects.equals(response.getType(), ApiParam.REP_HEARTBEAT)){
            EleLogs eleLogs = new EleLogs();
            eleLogs.setType(2);
            eleLogs.setNdid(edgeId);
            eleLogs.setReqTime(LocalDateTime.ofEpochSecond(Long.parseLong(registerDTO.getTimestamp()), 0, ZoneOffset.ofHours(8)));
            eleLogs.setInfo(response.getMsg());
            eleLogs.setCreateTime(LocalDateTime.now());
            eleLogsService.addLogs(eleLogs);
        }
        //回复装置信息
        publisher.send("/device/pltrep/"+version+"/" + edgeId,result,1,false);

//        询问模板数据 暂时线下传递模板数据
//        Gson gson = new Gson();
//        AccessDTO.AccessResponse response = gson.fromJson(result,AccessDTO.AccessResponse.class);
//        if (response.getCode() == Integer.parseInt(EnergyResponseEnum.NO_MODEL_FIND.getCode())){
//            AskDataDTO.AskDataRequest askDataDTO = new AskDataDTO.AskDataRequest();
//            askDataDTO.setTimestamp(Long.toString(System.currentTimeMillis()/1000));
//            askDataDTO.setLevel(0);
//            askDataDTO.setType(ApiParam.CMD_DEV_DATA);
//            AskDataParamDTO askDataParamDTO = new AskDataParamDTO();
//            askDataParamDTO.setDataType(DataType.TEMPLATE);
//            askDataParamDTO.setOperate(ModelState.READ);
//            askDataParamDTO.setStartTime(Long.toString(System.currentTimeMillis()/1000));
//            askDataDTO.setParam(askDataParamDTO);
//            publisher.send("/platform/command/v1/" + edgeId,gson.toJson(askDataDTO),1,false);
//        }
    }


    /**
     * 获取模板信息
     */
    @MqttSubscribe(value = "/platform/reply/{version}/{edgeId}",qos = 1)
    public void replyTemplate(String topic, MqttMessage message, @NamedValue("edgeId") String edgeId, @Payload String payload) {
        String result = modelService.deviceData(new String(message.getPayload(), StandardCharsets.UTF_8));
        //模板发生变更通知其他云服务
        Gson gson = new Gson();
        RegisterDTO.RegisterResponse response = gson.fromJson(result, RegisterDTO.RegisterResponse.class);
        if (Objects.equals(response.getCode(),200)){
            DeviceOperateDTO deviceOperateDTO = new DeviceOperateDTO();
            deviceOperateDTO.setTime(Long.toString(System.currentTimeMillis()));
            deviceOperateDTO.setMessage("模板更新");
            deviceOperateDTO.setType("001");
            publisher.send("/device/operate",gson.toJson(deviceOperateDTO),1,false);
        }
    }

    /**
     * 获取网关订阅的主题
     */
    @MqttSubscribe(value = "/device/topic/{edgeId}",qos = 1)
    public void subscribeTopic(String topic, MqttMessage message, @NamedValue("edgeId") String edgeId, @Payload String payload) {
        modelService.subscribeTopic(new String(message.getPayload(), StandardCharsets.UTF_8),edgeId);
    }

}
