/*
 * 文 件 名:  GeekOpenService
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/2/27
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.handle;

import com.alibaba.fastjson2.JSONObject;
import com.huashe.common.exception.Assert;
import com.huashe.common.exception.BusinessException;
import com.huashe.common.utils.ThreadUtils;
import com.ruoyi.ems.core.ObjectCache;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.domain.EmsObjAbilityCallLog;
import com.ruoyi.ems.domain.MeterDevice;
import com.ruoyi.ems.enums.DevOnlineStatus;
import com.ruoyi.ems.model.AbilityPayload;
import com.ruoyi.ems.model.CallResponse;
import com.ruoyi.ems.model.MqttCacheMsg;
import com.ruoyi.ems.model.QueryDevice;
import com.ruoyi.ems.util.IdUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * GeekOpen 断路器服务层
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/2/27]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service
public class GeekOpenCbHandler extends BaseMeterDevHandler {
    private static final Logger log = LoggerFactory.getLogger(GeekOpenCbHandler.class);

    @Autowired
    private ObjectCache messageCache;

    // 主题前缀
    private static final String TOPIC_PREFIX = "/device/dlq/";

    // 设备模型代码
    private static final String MODE_CODE = "M_W2_QF_GEEKOPEN";

    /**
     * 能力执行
     *
     * @param abilityParam 执行参数
     * @return 响应
     */
    @Override
    public CallResponse<Void> call(AbilityPayload abilityParam) {
        CallResponse<Void> callResponse = null;

        JSONObject sendObject = JSONObject.parseObject(abilityParam.getAbilityParam());
        String type = sendObject.getString("type");
        String deviceCode = abilityParam.getObjCode();
        String messageId = StringUtils.equals("statistic", type) ? "auto" : ("CALL-" + IdUtils.generateMessageId());
        String msgBody = addMsgId(abilityParam.getAbilityParam(), "messageId", messageId);

        // 发送消息到MQTT服务器
        long sendTime = System.currentTimeMillis();
        String topic = TOPIC_PREFIX + deviceCode;
        sendMqttMsg(topic, msgBody, 2, false);

        // 需要监测回包的流程
        if (StringUtils.equals(type, "event")
            || (StringUtils.equals(type, "setting")
            && (sendObject.containsKey("keyLock") || sendObject.containsKey("timerEnable") || sendObject.containsKey("onState")))) {
            // 写入日志
            EmsObjAbilityCallLog logItem = saveCallLog(abilityParam, sendTime, 1);

            while (true) {
                MqttCacheMsg cacheMsg = messageCache.readDevResponse(messageId);

                if (null != cacheMsg) {
                    String receiveParam = cacheMsg.getPayload();
                    JSONObject receiveObject = JSONObject.parseObject(receiveParam);
                    callResponse = checkResult(sendObject, receiveObject);
                    updateCallLog(logItem, cacheMsg, callResponse.getCode() == 0 ? 0 : 2);

                    break;
                }

                ThreadUtils.sleep(100);

                if (System.currentTimeMillis() - sendTime > 30000) {
                    logItem.setResPayload("响应超时");
                    logItem.setCallStatus(2);
                    objAbilityCallLogService.updateLog(logItem);
                    callResponse = new CallResponse<>(-1, "响应超时!");
                    break;
                }
            }
        }
        else {
            saveCallLog(abilityParam, sendTime, 0);
            callResponse = new CallResponse<>(0, "执行成功!");
        }

        return callResponse;
    }

    @Async("msgHandleExecutor")
    @Override
    public void msgHandle(String deviceCode, String payload) {
        try {
            EmsDevice device = deviceService.selectByCode(deviceCode);

            if (null != device) {
                JSONObject msgBody = JSONObject.parseObject(payload);
                String messageId = msgBody.getString("messageId");

                // 自动上报数据: 1.更新属性值，2.更新电量计量数据
                if (StringUtils.equals("auto", messageId)) {
                    updateAutoAttr(device, msgBody);
                    saveReportLog(deviceCode, device.getDeviceModel(), "电量上报", payload);
                }
                // 前序调用的响应消息：1.写入消息队列，2.更新属性值
                else if (StringUtils.isNotEmpty(messageId) && StringUtils.startsWith(messageId, "CALL-")) {
                    MqttCacheMsg mqttCacheMsg = new MqttCacheMsg(messageId, deviceCode, new Date(), payload);
                    messageCache.setDevResCache(messageId, mqttCacheMsg);
                    updateBaseAttr(device, msgBody);
                }
                // 设备同步数据（INFO类，协议类）：更新基础属性值
                else {
                    updateBaseAttr(device, msgBody);
                    saveReportLog(deviceCode, device.getDeviceModel(), "信息上报", payload);
                }

                // 设备消息抵达，将数据库离线状态改为在线
                refreshStatus(device, DevOnlineStatus.ONLINE);
                // 设备消息抵达，更新最后消息时间
                updateMsgTime(device, new Date());
            }
            else {
                log.warn("接收消息，设备未注册, deviceCode:{}\nmessageBody:{}", deviceCode, payload);
            }
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 获取设备列表
     * @return 设备列表
     */
    @Override
    public List<EmsDevice> getDeviceList() {
        QueryDevice queryDevice = new QueryDevice();
        queryDevice.setDeviceModel(MODE_CODE);
        return deviceService.selectList(queryDevice);
    }

    @Override
    public List<MeterDevice> getMeterDeviceList() {
        QueryDevice queryDevice = new QueryDevice();
        queryDevice.setDeviceModel("M_W2_QF_GEEKOPEN");
        queryDevice.setMeterCls(45);
        queryDevice.setColMode(0);
        return meterDeviceService.selectByModel(queryDevice);
    }

    /**
     * 更新基础属性值
     *
     * @param device   设备信息
     * @param jsonBody jsonBody 消息体
     */
    private void updateBaseAttr(EmsDevice device, JSONObject jsonBody) {
        updateAttr(device, jsonBody, "key");
        updateAttr(device, jsonBody, "iccid");
        updateAttr(device, jsonBody, "imei");
        updateAttr(device, jsonBody, "signal");
        updateAttr(device, jsonBody, "version");
        updateAttr(device, jsonBody, "timerEnable");
        updateAttr(device, jsonBody, "timerInterval");
        updateAttr(device, jsonBody, "keyLock");
        updateAttr(device, jsonBody, "onState");
        updateAttr(device, jsonBody, "resetLock");

        // 协议信息
        updateAttr(device, jsonBody, "protocol");
        updateAttr(device, jsonBody, "clientId");
        updateAttr(device, jsonBody, "server");
        updateAttr(device, jsonBody, "port");
        updateAttr(device, jsonBody, "username");
        updateAttr(device, jsonBody, "publish");
        updateAttr(device, jsonBody, "subcribe");
    }

    /**
     * 更新自动上报属性值
     *
     * @param device   设备信息
     * @param jsonBody jsonBody 消息体
     */
    private void updateAutoAttr(EmsDevice device, JSONObject jsonBody) {
        updateAttr(device, jsonBody, "voltage");
        updateAttr(device, jsonBody, "current");
        updateAttr(device, jsonBody, "power");
        updateAttr(device, jsonBody, "energy");
    }

    private CallResponse<Void> checkResult(JSONObject sendObject, JSONObject receiveObject) {
        CallResponse<Void> response = new CallResponse<>();

        try {
            String type = sendObject.getString("type");

            if (StringUtils.equals(type, "event")) {
                String sendKeyValue = sendObject.getString("key");
                String receiveKeyValue = receiveObject.getString("key");
                Assert.isTrue(StringUtils.equals(sendKeyValue, receiveKeyValue), -1, "响应参数key校验失败!");
            }
            else if (StringUtils.equals(type, "setting")) {
                if (sendObject.containsKey("keyLock")) {
                    String sendKeyLockValue = sendObject.getString("keyLock");
                    String receiveKeyLockValue = receiveObject.getString("keyLock");
                    Assert.isTrue(StringUtils.equals(sendKeyLockValue, receiveKeyLockValue), -1,
                        "响应参数keyLock校验失败!");
                }
                else if (sendObject.containsKey("timerEnable") && sendObject.containsKey("timerInterval")) {
                    String sendTimerEnableValue = sendObject.getString("timerEnable");
                    String receiveTimerEnableValue = receiveObject.getString("timerEnable");
                    Assert.isTrue(StringUtils.equals(sendTimerEnableValue, receiveTimerEnableValue), -1,
                        "响应参数timerEnable校验失败!");
                    String sendTimerIntervalValue = sendObject.getString("timerInterval");
                    String receiveTimerIntervalValue = receiveObject.getString("timerInterval");
                    Assert.isTrue(StringUtils.equals(sendTimerIntervalValue, receiveTimerIntervalValue), -1,
                        "响应参数timerInterval校验失败!");
                }
                else if (sendObject.containsKey("onState")) {
                    String sendOnStateValue = sendObject.getString("onState");
                    String receiveOnStateValue = receiveObject.getString("onState");
                    Assert.isTrue(StringUtils.equals(sendOnStateValue, receiveOnStateValue), -1,
                        "响应参数onState校验失败!");
                }
            }

            response.setCode(0);
            response.setMessage("执行成功!");
        }
        catch (BusinessException e) {
            log.warn(e.getMessage());
            response.setCode(e.getCode());
            response.setMessage(e.getMessage());
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            response.setCode(-1);
            response.setMessage("内部错误!");
        }

        return response;
    }
}