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

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.ems.config.AcrelConfig;
import com.ruoyi.ems.core.Acrel3000Template;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.domain.EmsObjAttr;
import com.ruoyi.ems.domain.EmsObjAttrValue;
import com.ruoyi.ems.domain.MeterDevice;
import com.ruoyi.ems.enums.DevObjType;
import com.ruoyi.ems.model.AbilityPayload;
import com.ruoyi.ems.model.CallResponse;
import com.ruoyi.ems.model.QueryDevice;
import com.ruoyi.ems.model.acrel.Circuit;
import com.ruoyi.ems.model.acrel.MeterKeyValue;
import com.ruoyi.ems.model.acrel.MeterUse;
import com.ruoyi.ems.service.IEmsObjAttrService;
import com.ruoyi.ems.util.PingUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 安科瑞电力监控模块handle
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/10/20]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service
public class AcrelElecMonitorHandler extends BaseMeterDevHandler {
    private static final Logger log = LoggerFactory.getLogger(AcrelElecMonitorHandler.class);

    // 对接系统
    private static final String SYS_MODE_CODE = "M_W4_SYS_ELEC_MONITOR";

    // 保护装置模型代码
    private static final String MONITOR_BHZZ_MODE_CODE = "M_W4_DEV_ELEC_MONITOR_BHZZ";

    // 电表模型代码
    private static final String MONITOR_DB_MODE_CODE = "M_W4_DEV_ELEC_MONITOR_DB";

    // 设备子系统代码
    private static final String SUBSYSTEM_CODE = "SYS_DLJK";

    @Resource
    private AcrelConfig config;

    @Autowired
    private IEmsObjAttrService objAttrService;

    @Override
    public List<MeterDevice> getMeterDeviceList() {
        return Collections.emptyList();
    }

    @Override
    public List<EmsDevice> getDeviceList() {
        QueryDevice queryDevice = new QueryDevice();
        queryDevice.setSubsystemCode(SUBSYSTEM_CODE);
        return deviceService.selectList(queryDevice);
    }

    @Override
    public CallResponse<Void> call(AbilityPayload abilityParam) {
        CallResponse<Void> callResponse = null;

        try {
            if (DevObjType.SYSTEM.getCode() == abilityParam.getObjType()) {
                switch (abilityParam.getAbilityKey()) {
                    case "GetDeviceList":
                        CompletableFuture.runAsync(this::execGetDeviceList);
                        break;
                    case "SyncDevAttrAll":
                        CompletableFuture.runAsync(this::execSyncDevAttrAll);
                        break;
                    default:
                        throw new UnsupportedOperationException("不支持的abilityKey");
                }
            }
            else if (DevObjType.DEVC.getCode() == abilityParam.getObjType()) {
                switch (abilityParam.getAbilityKey()) {
                    case "SyncDevAttr":
                        execSyncDevAttr(abilityParam.getObjCode(), abilityParam.getModelCode());
                        break;
                    default:
                        throw new UnsupportedOperationException("不支持的abilityKey");
                }
            }

            callResponse = new CallResponse<>(0, "成功");
        }
        catch (Exception e) {
            callResponse = new CallResponse<>(-1, e.getMessage());
            log.error("调用ability异常", e);
        }

        return callResponse;
    }

    @Override
    public void refreshOnline() {
        try {
            // 1. 从URL中提取IP地址
            String url = config.getUrl();
            if (StringUtils.isBlank(url)) {
                log.warn("电力监控系统URL配置为空，跳过心跳检测");
                return;
            }

            String ipAddress = PingUtils.extractIpFromUrl(url);
            if (StringUtils.isBlank(ipAddress)) {
                log.warn("无法从URL中提取IP地址: {}", url);
                return;
            }

            // 2. 执行ping检测
            boolean isOnline = PingUtils.pingHost(ipAddress, 3000); // 3秒超时

            // 3. 获取当前系统状态
            String statusKey = "interfaceStatus";

            // 查询当前状态
            EmsObjAttrValue currentStatus = objAttrValueService.selectObjAttrValue(SYS_MODE_CODE, SUBSYSTEM_CODE,
                statusKey);

            String newStatus = isOnline ? "1" : "0";
            String oldStatus = currentStatus != null ? currentStatus.getAttrValue() : null;

            // 4. 状态发生变化时更新并记录
            if (!StringUtils.equals(oldStatus, newStatus)) {
                log.info("电力监控系统连接状态变化: {} -> {}, IP: {}", oldStatus, newStatus, ipAddress);

                // 更新系统属性状态
                objAttrValueService.updateObjAttrValue(SYS_MODE_CODE, SUBSYSTEM_CODE, statusKey, newStatus);

                String key = isOnline ? "connect" : "disconnect";
                triggerEvent(SYS_MODE_CODE, SUBSYSTEM_CODE, key, null, new Date());
            }

            // 5. 记录心跳日志（可选，用于调试）
            log.debug("电力监控系统心跳检测完成 - IP: {}, 状态: {}", ipAddress, isOnline ? "在线" : "离线");
        }
        catch (Exception e) {
            log.error("电力监控系统心跳检测异常", e);
        }
    }

    public void execGetDeviceList() {
        try {
            // 删除数据库设备
            QueryDevice param = new QueryDevice();
            param.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> dbDevs = deviceService.selectList(param);

            if (CollectionUtils.isNotEmpty(dbDevs)) {
                for (EmsDevice emsDevice : dbDevs) {
                    deviceService.deleteDevice(emsDevice.getDeviceModel(), emsDevice.getDeviceCode());
                }
            }

            objAttrValueService.deleteByObjCode(MONITOR_BHZZ_MODE_CODE, null);
            objAttrValueService.deleteByObjCode(MONITOR_DB_MODE_CODE, null);

            // 执行采集
            String[] subIds = StringUtils.split(config.getSubIds(), ",");

            if (ArrayUtils.isNotEmpty(subIds)) {
                for (String subId : subIds) {
                    getAreaDeviceList(subId);
                }
            }
        }
        catch (Exception e) {
            log.error("execGetDeviceList fail!", e);
        }
    }

    public void execSyncDevAttrAll() {
        try {
            // 执行采集
            String[] subIds = StringUtils.split(config.getSubIds(), ",");
            // 采集同步设备
            Acrel3000Template template = new Acrel3000Template(config.getUrl());

            for (String subId : subIds) {
                List<MeterUse> meterUseList = template.getMeterUseInfoList(subId);
                meterUseList = meterUseList.stream().filter(this::meterUseList).collect(Collectors.toList());
                List<Circuit> circuitList = template.getCircuitInfoTree(subId);
                Map<String, Circuit> circuitParentMap = circuitList.stream()
                    .collect(Collectors.toMap(Circuit::getMeterCode, Function.identity()));

                if (CollectionUtils.isNotEmpty(meterUseList)) {
                    for (MeterUse meterUse : meterUseList) {
                        String objCode = circuitParentMap.containsKey(meterUse.getMeterCode()) ?
                            String.format("W4-E-%s", meterUse.getMeterCode()) :
                            meterUse.getMeterCode();

                        if (StringUtils.equals("01001", meterUse.getMeterTypeCode())) {
                            refreshDevAttr(objCode, MONITOR_DB_MODE_CODE, meterUse, template);
                        }
                        else if (StringUtils.equals("01002", meterUse.getMeterTypeCode())) {
                            refreshDevAttr(objCode, MONITOR_BHZZ_MODE_CODE, meterUse, template);
                        }
                    }
                }
            }
        }
        catch (Exception e) {
            log.error("execSyncDevAttrAll fail!", e);
        }
    }

    public void execSyncDevAttr(String objCode, String modelCode) {
        try {
            EmsObjAttrValue subIdObj = objAttrValueService.selectObjAttrValue(modelCode, objCode, "subId");
            EmsObjAttrValue meterCodeObj = objAttrValueService.selectObjAttrValue(modelCode, objCode, "deviceCode");

            if (null != subIdObj && null != meterCodeObj) {
                MeterUse meterUse = new MeterUse();
                meterUse.setSubId(subIdObj.getAttrValue());
                meterUse.setMeterCode(meterCodeObj.getAttrValue());

                Acrel3000Template template = new Acrel3000Template(config.getUrl());
                refreshDevAttr(objCode, modelCode, meterUse, template);
            }
        }
        catch (Exception e) {
            log.error("execSyncDevAttr fail!", e);
        }
    }

    public void getAreaDeviceList(String subId) {
        // 采集同步设备
        Acrel3000Template template = new Acrel3000Template(config.getUrl());
        List<MeterUse> meterUseList = template.getMeterUseInfoList(subId);
        meterUseList = meterUseList.stream().filter(this::meterUseList).collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(meterUseList)) {
            Map<String, MeterUse> meterUseMap = meterUseList.stream()
                .collect(Collectors.toMap(MeterUse::getMeterCode, Function.identity()));

            List<Circuit> circuitList = template.getCircuitInfoTree(subId);

            for (Circuit circuit : circuitList) {
                if (meterUseMap.containsKey(circuit.getMeterCode())) {
                    MeterUse meterUse = meterUseMap.get(circuit.getMeterCode());

                    // 构造设备对象
                    EmsDevice device = convertDevice(meterUse);
                    deviceService.insertEmsDevice(device);

                    // 设备属性
                    List<EmsObjAttrValue> attrValues = buildDeviceAttr(device.getDeviceCode(), device.getDeviceModel(),
                        circuit, meterUseMap, template);

                    if (CollectionUtils.isNotEmpty(attrValues)) {
                        objAttrValueService.insertBatch(attrValues);
                    }
                }
            }
        }
    }

    private void refreshDevAttr(String objCode, String modelCode, MeterUse meterUse, Acrel3000Template template) {
        // 查询数据库对象属性集合
        List<EmsObjAttrValue> dbAttrValues = objAttrValueService.selectByObjCode(modelCode, objCode);

        if (CollectionUtils.isNotEmpty(dbAttrValues)) {
            Map<String, EmsObjAttrValue> vMap = dbAttrValues.stream()
                .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));

            checkAndUpdate(vMap, objCode, modelCode, "deviceStatus", String.valueOf(convertStatus(meterUse)));

            List<EmsObjAttr> objAttrList = objAttrService.selectByModelCode(modelCode);
            Set<String> attrKeys = objAttrList.stream().map(EmsObjAttr::getAttrKey).collect(Collectors.toSet());

            List<MeterKeyValue> meterKeyValueList = template.getMeterParamValueByKey(meterUse.getSubId(),
                meterUse.getMeterCode());
            meterKeyValueFormat(meterKeyValueList, "Switch");

            for (MeterKeyValue meterKeyValue : meterKeyValueList) {
                if (attrKeys.contains(meterKeyValue.getParamCode())) {
                    checkAndUpdate(vMap, objCode, modelCode, meterKeyValue.getParamCode(), meterKeyValue.getValue());
                }
            }
        }
    }

    private List<EmsObjAttrValue> buildDeviceAttr(String objCode, String modelCode, Circuit circuit,
        Map<String, MeterUse> meterUseMap, Acrel3000Template template) {
        // 主节点设备自身属性获取
        MeterUse parentMeterUse = meterUseMap.get(circuit.getMeterCode());
        List<EmsObjAttrValue> attrValues = new ArrayList<>(
            getDeviceAttrFromSys(objCode, modelCode, convertStatus(parentMeterUse), circuit, template));

        if (circuit.getInComIng() && CollectionUtils.isNotEmpty(circuit.getChildren())) {
            JSONArray subDevArray = new JSONArray();

            for (Circuit subCircuit : circuit.getChildren()) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("deviceCode", subCircuit.getMeterCode());
                jsonObject.put("modelCode", modelCode);
                subDevArray.add(jsonObject);

                MeterUse subMeterUse = meterUseMap.get(subCircuit.getMeterCode());
                // 子节点设备属性获取
                attrValues.addAll(
                    getDeviceAttrFromSys(subCircuit.getMeterCode(), modelCode, convertStatus(subMeterUse), subCircuit,
                        template));
            }

            attrValues.add(new EmsObjAttrValue(objCode, modelCode, "subDev", subDevArray.toString()));
        }

        return attrValues;
    }

    private List<EmsObjAttrValue> getDeviceAttrFromSys(String objCode, String modelCode, Integer deviceStatus,
        Circuit circuit, Acrel3000Template template) {
        List<EmsObjAttrValue> retList = new ArrayList<>();
        retList.add(new EmsObjAttrValue(objCode, modelCode, "subId", circuit.getSubId()));
        retList.add(new EmsObjAttrValue(objCode, modelCode, "subName", circuit.getSubName()));
        retList.add(new EmsObjAttrValue(objCode, modelCode, "deviceName", circuit.getCircuitName()));
        retList.add(new EmsObjAttrValue(objCode, modelCode, "deviceCode", circuit.getMeterCode()));
        retList.add(new EmsObjAttrValue(objCode, modelCode, "deviceStatus", deviceStatus.toString()));

        List<MeterKeyValue> meterKeyValueList = template.getMeterParamValueByKey(circuit.getSubId(),
            circuit.getMeterCode());

        if (CollectionUtils.isNotEmpty(meterKeyValueList)) {
            List<EmsObjAttr> objAttrList = objAttrService.selectByModelCode(modelCode);

            Map<String, MeterKeyValue> map = meterKeyValueList.stream()
                .collect(Collectors.toMap(MeterKeyValue::getParamCode, Function.identity()));
            // 值格式化
            meterKeyValueFormat(map, "Switch");

            for (EmsObjAttr objAttr : objAttrList) {
                if (map.containsKey(objAttr.getAttrKey())) {
                    MeterKeyValue meterKeyValue = map.get(objAttr.getAttrKey());
                    retList.add(
                        new EmsObjAttrValue(objCode, modelCode, objAttr.getAttrKey(), meterKeyValue.getValue()));
                }
            }
        }

        return retList;
    }

    private void meterKeyValueFormat(List<MeterKeyValue> list, String key) {
        Map<String, MeterKeyValue> map = list.stream()
            .collect(Collectors.toMap(MeterKeyValue::getParamCode, Function.identity()));
        meterKeyValueFormat(map, key);
    }

    private void meterKeyValueFormat(Map<String, MeterKeyValue> map, String key) {
        MeterKeyValue switchMeterKeyValue = map.get(key);

        if (null != switchMeterKeyValue && null != switchMeterKeyValue.getValue()) {
            switchMeterKeyValue.setValue(switchMeterKeyValue.getValue().split("\\.")[0]);
        }
    }

    private EmsDevice convertDevice(MeterUse meterUse) {
        EmsDevice device = new EmsDevice();
        device.setDeviceCode(String.format("W4-E-%s", meterUse.getMeterCode()));
        device.setDeviceName(meterUse.getMeterName());
        device.setDeviceBrand("安科瑞");
        device.setDeviceSpec(null);
        device.setDeviceStatus(convertStatus(meterUse));
        device.setLocation(meterUse.getSubName());
        device.setPsCode("SM");
        device.setSubsystemCode(SUBSYSTEM_CODE);

        if (StringUtils.equals("01001", meterUse.getMeterTypeCode())) {
            device.setDeviceModel(MONITOR_DB_MODE_CODE);
        }
        else if (StringUtils.equals("01002", meterUse.getMeterTypeCode())) {
            device.setDeviceModel(MONITOR_BHZZ_MODE_CODE);
        }

        if (StringUtils.equals("10100002", meterUse.getSubId())) {
            device.setLocationRef("321283124S300100");
            device.setAreaCode("321283124S3001");
            device.setRefFacs("NH01");
        }
        else if (StringUtils.equals("10100003", meterUse.getSubId())) {
            device.setLocationRef("321283124S300200");
            device.setAreaCode("321283124S3002");
            device.setRefFacs("NH02");
        }

        return device;
    }

    private Integer convertStatus(MeterUse meterUse) {
        if (null != meterUse && null != meterUse.getDisConnect()) {
            return meterUse.getDisConnect() ? 0 : 1;
        }
        else {
            return 1;
        }
    }

    private boolean meterUseList(MeterUse meterUse) {
        return
            (StringUtils.equals(meterUse.getMeterTypeCode(), "01001") && !StringUtils.contains(meterUse.getMeterName(),
                "温感")) || StringUtils.equals(meterUse.getMeterTypeCode(), "01002");
    }
}