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

import com.huashe.common.utils.DateUtils;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.domain.EmsObjAbilityCallLog;
import com.ruoyi.ems.domain.EmsObjAttrValue;
import com.ruoyi.ems.domain.EmsObjEventLog;
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.service.IElecMeterHService;
import com.ruoyi.ems.service.IElecPgSupplyHService;
import com.ruoyi.ems.service.IEmsDeviceService;
import com.ruoyi.ems.service.IEmsFacsService;
import com.ruoyi.ems.service.IEmsObjAbilityCallLogService;
import com.ruoyi.ems.service.IEmsObjAttrValueService;
import com.ruoyi.ems.service.IEmsObjEventLogService;
import com.ruoyi.ems.service.IFdEnergyPriceConfigService;
import com.ruoyi.ems.service.IPriceService;
import com.ruoyi.ems.service.IWaterMeterHService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

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

/**
 * 设备处理基类
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/4/15]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Slf4j
public abstract class BaseDevHandler {
    @Autowired
    protected RedisService redisService;

    @Autowired
    protected IEmsFacsService facsService;

    @Autowired
    protected IEmsDeviceService deviceService;

    @Autowired
    protected IEmsObjAttrValueService objAttrValueService;

    @Autowired
    protected IElecMeterHService elecMeterHService;

    @Autowired
    protected IWaterMeterHService waterMeterHService;

    @Autowired
    protected IPriceService priceService;

    @Autowired
    protected IFdEnergyPriceConfigService fdEnergyPriceConfigService;

    @Autowired
    protected IEmsObjAbilityCallLogService objAbilityCallLogService;

    @Autowired
    protected IEmsObjEventLogService objEventLogService;

    @Autowired
    protected IElecPgSupplyHService pgSupplyHService;

    /**
     * 抽象方法，用于能力调用
     *
     * @param abilityParam 能力参数
     * @return 处理结果字符串
     */
    public abstract CallResponse<Void> call(AbilityPayload abilityParam);

    /**
     * 获取设备列表
     *
     * @return 设备列表
     */
    public abstract List<EmsDevice> getDeviceList();

    /**
     * 最后一次消息时间缓存key
     */
    protected static final String MQTT_LAST_TIME = "mqttLastMsgTime";

    /**
     * 更新最后消息时
     *
     * @param device    设备
     * @param timeValue 时间值
     */
    public void updateMsgTime(EmsDevice device, Date timeValue) {
        try {
            String dateTime = DateUtils.dateToString(timeValue, DateUtils.YYYY_MM_DD_HH_MM_SS);

            // 更新缓存
            updateCacheAfterSuccess(device.getDeviceCode(), MQTT_LAST_TIME, dateTime);
        }
        catch (Exception e) {
            log.error("刷新缓存消息时间失败!", e);
        }
    }

    /**
     * 更新缓存值
     *
     * @param deviceCode 设备信息
     * @param attrKey    属性值
     * @param newValue
     */
    public void updateCacheAfterSuccess(String deviceCode, String attrKey, String newValue) {
        redisService.setCacheMapValue(deviceCode, attrKey, newValue);
    }

    /**
     * 刷新设备状态
     *
     * @param device 设备信息
     */
    public void refreshStatus(EmsDevice device, DevOnlineStatus status) {
        if (null == device.getDeviceStatus() || device.getDeviceStatus() != status.getCode()) {
            device.setDeviceStatus(status.getCode());
            deviceService.updateEmsDevice(device);
            triggerEvent(device, status == DevOnlineStatus.ONLINE ? "online" : "offline", null, new Date());
            log.debug("设备[{}]{}...", device.getDeviceCode(), status == DevOnlineStatus.ONLINE ? "上线" : "下线");
        }
    }

    /**
     * 触发设备事件
     *
     * @param device   设备信息
     * @param eventKey 事件标记
     * @param detail   事件详情
     * @param date     时间戳
     */
    public void triggerEvent(EmsDevice device, String eventKey, String detail, Date date) {
        EmsObjEventLog eventLog = new EmsObjEventLog();
        eventLog.setObjCode(device.getDeviceCode());
        eventLog.setModelCode(device.getDeviceModel());
        eventLog.setEventKey(eventKey);
        eventLog.setEventTime(date);
        eventLog.setEventDetail(detail);
        objEventLogService.insertLog(eventLog);
    }

    /**
     * 触发设备事件
     *
     * @param modelCode 模型代码
     * @param objCode   对象编码
     * @param detail    事件详情
     * @param date      时间戳
     */
    public void triggerEvent(String modelCode, String objCode, String eventKey, String detail, Date date) {
        EmsObjEventLog eventLog = new EmsObjEventLog();
        eventLog.setModelCode(modelCode);
        eventLog.setObjCode(objCode);
        eventLog.setEventKey(eventKey);
        eventLog.setEventTime(date);
        eventLog.setEventDetail(detail);
        objEventLogService.insertLog(eventLog);
    }

    protected EmsObjAbilityCallLog saveCallLog(AbilityPayload abilityParam, String callPayload, long sendTime, int callStatus) {
        EmsObjAbilityCallLog objAbilityCallLog = new EmsObjAbilityCallLog();
        objAbilityCallLog.setObjCode(abilityParam.getObjCode());
        objAbilityCallLog.setModelCode(abilityParam.getModelCode());
        objAbilityCallLog.setAbilityKey(abilityParam.getAbilityKey());
        objAbilityCallLog.setCallTime(new Date(sendTime));
        objAbilityCallLog.setCallPayload(callPayload);
        objAbilityCallLog.setCallStatus(callStatus);
        objAbilityCallLogService.addLog(objAbilityCallLog);
        return objAbilityCallLog;
    }

    protected void updateCallLog(EmsObjAbilityCallLog objAbilityCallLog, MqttCacheMsg cacheMsg, int callStatus) {
        objAbilityCallLog.setResTime(cacheMsg.getReceiveTime());
        objAbilityCallLog.setResPayload(cacheMsg.getPayload());
        objAbilityCallLog.setCallStatus(callStatus);
        objAbilityCallLogService.updateLog(objAbilityCallLog);
    }

    protected EmsObjAbilityCallLog saveCallLog(String objCode, String modelCode, String abilityKey, Integer callStatus,
        String callPayload, String resPayload) {
        EmsObjAbilityCallLog objAbilityCallLog = new EmsObjAbilityCallLog();
        objAbilityCallLog.setObjCode(objCode);
        objAbilityCallLog.setModelCode(modelCode);
        objAbilityCallLog.setAbilityKey(abilityKey);
        objAbilityCallLog.setCallTime(new Date());
        objAbilityCallLog.setCallPayload(callPayload);
        objAbilityCallLog.setCallStatus(callStatus);
        objAbilityCallLog.setResTime(new Date());
        objAbilityCallLog.setResPayload(resPayload);
        objAbilityCallLogService.addLog(objAbilityCallLog);
        return objAbilityCallLog;
    }

    public abstract void refreshOnline();

    protected void checkAndUpdate(Map<String, EmsObjAttrValue> objAttrValueMap, String objCode, String modelCode,
        String key, String newValue) {
        EmsObjAttrValue objAttrValue = objAttrValueMap.get(key);

        if (null != objAttrValue) {
            if (!StringUtils.equals(objAttrValue.getAttrValue(), newValue)) {
                objAttrValueService.updateObjAttrValue(modelCode, objCode, key, newValue);
            }
        }
        else {
            objAttrValue = new EmsObjAttrValue(objCode, modelCode, key, newValue);
            objAttrValueService.mergeObjAttrValue(objAttrValue);
        }
    }
}