/*
 * 文 件 名:  GrowattHandler
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  古瑞瓦特-光伏适配处理Handler
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/18
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  完善采集器和逆变器数据同步功能
 */
package com.ruoyi.ems.handle;

import com.alibaba.fastjson2.JSONObject;
import com.huashe.common.utils.DateUtils;
import com.ruoyi.ems.config.GrowattConfig;
import com.ruoyi.ems.core.GrowattTemplate;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.domain.EmsObjAttrValue;
import com.ruoyi.ems.enums.DevObjType;
import com.ruoyi.ems.enums.DevOnlineStatus;
import com.ruoyi.ems.model.AbilityPayload;
import com.ruoyi.ems.model.CallResponse;
import com.ruoyi.ems.model.QueryDevice;
import com.ruoyi.ems.model.growatt.DataLogger;
import com.ruoyi.ems.model.growatt.DeviceInfo;
import org.apache.commons.collections4.CollectionUtils;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
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;

/**
 * 古瑞瓦特-光伏适配处理Handler
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/18]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service
public class GrowattHandler extends BaseDevHandler {
    private static final Logger log = LoggerFactory.getLogger(GrowattHandler.class);

    // 光伏系统模型代码
    private static final String SYS_MODEL_CODE = "M_E5_SYS_PHOTOVOLTAIC";

    // 光伏采集器模型代码
    private static final String DEV_MODEL_COL = "M_W2_DEV_PHOTOVOLTAIC_COL";

    // 光伏逆变器模型代码
    private static final String DEV_MODEL_INVERTER = "M_E5_DEV_PHOTOVOLTAIC_INVERTER";

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

    // 逆变器设备类型（MAX类型）
    private static final int INVERTER_TYPE_MAX = 18;

    @Autowired
    private GrowattConfig config;

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

        try {
            if (DevObjType.SYSTEM.getCode() == abilityParam.getObjType()) {
                switch (abilityParam.getAbilityKey()) {
                    case "SyncDevCollector":
                        // 同步采集器数据
                        CompletableFuture.runAsync(this::execSyncDevCollector);
                        break;
                    case "SyncDevInverter":
                        // 同步逆变器列表数据
                        CompletableFuture.runAsync(this::execSyncDevInverter);
                        break;
                    case "CollectInverterData":
                        // 采集逆变器实时数据
                        CompletableFuture.runAsync(this::execCollectInverterData);
                        break;
                    case "SyncAll":
                        // 同步所有数据（采集器+逆变器+实时数据）
                        CompletableFuture.runAsync(this::execSyncAll);
                        break;
                    default:
                        throw new UnsupportedOperationException("不支持的abilityKey: " + abilityParam.getAbilityKey());
                }
            }
            else if (DevObjType.DEVC.getCode() == abilityParam.getObjType()) {
                if (StringUtils.equals(DEV_MODEL_COL, abilityParam.getModelCode())) {
                    // 采集器设备能力
                    switch (abilityParam.getAbilityKey()) {
                        case "SyncAttr":
                            execSyncCollectorAttr(abilityParam.getObjCode());
                            break;
                        default:
                            throw new UnsupportedOperationException(
                                "不支持的abilityKey: " + abilityParam.getAbilityKey());
                    }
                }
                else if (StringUtils.equals(DEV_MODEL_INVERTER, abilityParam.getModelCode())) {
                    // 逆变器设备能力
                    switch (abilityParam.getAbilityKey()) {
                        case "SyncAttr":
                            execSyncInverterAttr(abilityParam.getObjCode());
                            break;
                        default:
                            throw new UnsupportedOperationException(
                                "不支持的abilityKey: " + abilityParam.getAbilityKey());
                    }
                }
            }

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

        return callResponse;
    }

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

    @Override
    public void refreshOnline() {
        log.info("开始刷新光伏设备在线状态...");

        try {
            GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());

            // ==================== 第一步：刷新采集器在线状态 ====================
            List<String> plantList = config.getPlantList();
            if (CollectionUtils.isEmpty(plantList)) {
                log.warn("未配置电站ID列表");
                return;
            }

            // 从所有电站获取采集器列表
            List<DataLogger> allDataLoggers = new ArrayList<>();
            for (String plantId : plantList) {
                List<DataLogger> dataLoggers = template.getDatalogList(plantId);
                if (CollectionUtils.isNotEmpty(dataLoggers)) {
                    allDataLoggers.addAll(dataLoggers);
                }
            }

            if (CollectionUtils.isEmpty(allDataLoggers)) {
                log.warn("API返回采集器列表为空");
                return;
            }

            // 将API数据转为Map，key为sn
            Map<String, DataLogger> apiDataMap = allDataLoggers.stream()
                .collect(Collectors.toMap(DataLogger::getSn, Function.identity()));

            // 查询本地采集器设备
            QueryDevice queryCollector = new QueryDevice();
            queryCollector.setDeviceModel(DEV_MODEL_COL);
            queryCollector.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> collectorDevices = deviceService.selectList(queryCollector);

            // 采集器sn -> 在线状态 的映射（用于后续判断逆变器状态）
            Map<String, Boolean> collectorOnlineMap = new HashMap<>();

            for (EmsDevice device : collectorDevices) {
                EmsObjAttrValue snAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_COL, device.getDeviceCode(),
                    "sn");

                if (snAttr == null || StringUtils.isBlank(snAttr.getAttrValue())) {
                    continue;
                }

                String sn = snAttr.getAttrValue();
                DataLogger apiData = apiDataMap.get(sn);

                if (apiData == null) {
                    continue;
                }

                // lost=false 表示在线，lost=true 表示离线
                boolean isOnline = !apiData.isLost();
                collectorOnlineMap.put(sn, isOnline);

                int newStatus = isOnline ? DevOnlineStatus.ONLINE.getCode() : DevOnlineStatus.OFFLINE.getCode();
                if (device.getDeviceStatus() == null || device.getDeviceStatus() != newStatus) {
                    device.setDeviceStatus(newStatus);
                    deviceService.updateEmsDevice(device);
                    triggerEvent(device, isOnline ? "online" : "offline", null, new Date());
                    log.info("采集器 {} 状态更新为 {}", device.getDeviceCode(), isOnline ? "在线" : "离线");
                }
            }

            // ==================== 第二步：刷新逆变器在线状态 ====================
            // 逆变器的在线状态由其关联的采集器决定
            QueryDevice queryInverter = new QueryDevice();
            queryInverter.setDeviceModel(DEV_MODEL_INVERTER);
            queryInverter.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> inverterDevices = deviceService.selectList(queryInverter);

            for (EmsDevice device : inverterDevices) {
                // 获取逆变器关联的采集器sn（dataloggerSn属性）
                EmsObjAttrValue dataloggerSnAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_INVERTER,
                    device.getDeviceCode(), "dataloggerSn");

                if (dataloggerSnAttr == null || StringUtils.isBlank(dataloggerSnAttr.getAttrValue())) {
                    continue;
                }

                String dataloggerSn = dataloggerSnAttr.getAttrValue();

                // 根据关联的采集器状态判断逆变器状态
                Boolean collectorOnline = collectorOnlineMap.get(dataloggerSn);
                boolean isOnline = collectorOnline != null && collectorOnline;

                int newStatus = isOnline ? DevOnlineStatus.ONLINE.getCode() : DevOnlineStatus.OFFLINE.getCode();
                if (device.getDeviceStatus() == null || device.getDeviceStatus() != newStatus) {
                    device.setDeviceStatus(newStatus);
                    deviceService.updateEmsDevice(device);
                    triggerEvent(device, isOnline ? "online" : "offline", null, new Date());
                    log.info("逆变器 {} 状态更新为 {} (关联采集器:{})", device.getDeviceCode(),
                        isOnline ? "在线" : "离线", dataloggerSn);
                }
            }

            log.info("光伏设备在线状态刷新完成");

        }
        catch (Exception e) {
            log.error("刷新光伏设备在线状态异常", e);
        }
    }

    /**
     * 同步所有数据
     */
    public void execSyncAll() {
        log.info("开始同步光伏系统所有数据...");
        execSyncDevCollector();
        execSyncDevInverter();
        execCollectInverterData();
        log.info("光伏系统数据同步完成");
    }

    /**
     * 同步采集器数据
     * 调用API获取采集器列表，与本地数据库比对，更新状态和属性
     */
    public void execSyncDevCollector() {
        log.info("开始同步采集器数据...");

        try {
            GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());

            // 1. 从API获取所有电站的采集器列表
            List<DataLogger> allDataLoggers = new ArrayList<>();
            List<String> plantList = config.getPlantList();
            if (CollectionUtils.isEmpty(plantList)) {
                log.warn("未配置电站ID列表");
                return;
            }

            for (String plantId : plantList) {
                List<DataLogger> dataLoggers = template.getDatalogList(plantId);
                if (CollectionUtils.isNotEmpty(dataLoggers)) {
                    allDataLoggers.addAll(dataLoggers);
                }
                log.info("从电站 {} 获取到 {} 个采集器", plantId, dataLoggers.size());
            }

            if (CollectionUtils.isEmpty(allDataLoggers)) {
                log.warn("API返回采集器列表为空");
                return;
            }

            log.info("从API共获取到 {} 个采集器", allDataLoggers.size());

            // 将API数据转为Map，key为sn
            Map<String, DataLogger> apiDataMap = allDataLoggers.stream()
                .collect(Collectors.toMap(DataLogger::getSn, Function.identity(), (k1, k2) -> k1));

            // 2. 查询本地数据库中的采集器设备
            QueryDevice queryDevice = new QueryDevice();
            queryDevice.setDeviceModel(DEV_MODEL_COL);
            queryDevice.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> localDevices = deviceService.selectList(queryDevice);
            log.info("本地数据库有 {} 个采集器设备", localDevices.size());

            if (CollectionUtils.isEmpty(localDevices)) {
                log.warn("本地数据库无采集器设备");
                return;
            }

            // 3. 遍历本地设备，通过sn属性与API数据匹配
            for (EmsDevice device : localDevices) {
                try {
                    // 查询设备的sn属性
                    EmsObjAttrValue snAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_COL,
                        device.getDeviceCode(), "sn");

                    if (snAttr == null || StringUtils.isBlank(snAttr.getAttrValue())) {
                        log.warn("采集器设备 {} 无sn属性，跳过", device.getDeviceCode());
                        continue;
                    }

                    String sn = snAttr.getAttrValue();
                    DataLogger apiData = apiDataMap.get(sn);

                    if (apiData == null) {
                        log.warn("采集器 {} (sn={}) 在API中未找到", device.getDeviceCode(), sn);
                        continue;
                    }

                    // 4. 更新设备属性
                    List<EmsObjAttrValue> existingAttrs = objAttrValueService.selectByObjCode(DEV_MODEL_COL,
                        device.getDeviceCode());
                    Map<String, EmsObjAttrValue> attrMap = existingAttrs.stream()
                        .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));

                    // 更新或插入属性值
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_COL, "manufacturer",
                        apiData.getManufacturer());
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_COL, "model", apiData.getModel());
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_COL, "netMode", apiData.getNetMode());
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_COL, "type",
                        String.valueOf(apiData.getType()));

                    // lastUpdateTime 需要特殊处理
                    if (apiData.getUpdateTime() != null) {
                        String updateTimeStr = DateUtils.dateToString(apiData.getUpdateTime(), "yyyy-MM-dd HH:mm:ss");
                        checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_COL, "lastUpdateTime", updateTimeStr);
                    }

                    log.debug("采集器 {} 属性已更新", device.getDeviceCode());

                }
                catch (Exception e) {
                    log.error("处理采集器设备 {} 异常", device.getDeviceCode(), e);
                }
            }

            // 记录调用日志
            saveCallLog(SUBSYSTEM_CODE, SYS_MODEL_CODE, "SyncDevCollector", 0,
                "{\"plantList\":\"" + StringUtils.join(plantList, ",") + "\"}",
                "{\"count\":" + allDataLoggers.size() + "}");

            log.info("采集器数据同步完成");

        }
        catch (Exception e) {
            log.error("同步采集器数据异常", e);
            saveCallLog(SUBSYSTEM_CODE, SYS_MODEL_CODE, "SyncDevCollector", -1,
                "{\"plantList\":\"" + StringUtils.join(config.getPlantList(), ",") + "\"}", e.getMessage());
        }
    }

    /**
     * 同步逆变器列表数据
     * 调用API获取逆变器列表，与本地数据库比对，更新状态和属性
     */
    public void execSyncDevInverter() {
        log.info("开始同步逆变器列表数据...");

        try {
            GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());

            // 1. 从API获取所有电站的设备列表
            List<DeviceInfo> allDeviceList = new ArrayList<>();
            List<String> plantList = config.getPlantList();
            if (CollectionUtils.isEmpty(plantList)) {
                log.warn("未配置电站ID列表");
                return;
            }

            for (String plantId : plantList) {
                List<DeviceInfo> deviceList = template.getDeviceList(plantId);
                if (CollectionUtils.isNotEmpty(deviceList)) {
                    allDeviceList.addAll(deviceList);
                }
                log.info("从电站 {} 获取到 {} 个设备", plantId, deviceList.size());
            }

            if (CollectionUtils.isEmpty(allDeviceList)) {
                log.warn("API返回设备列表为空");
                return;
            }

            log.info("从API共获取到 {} 个设备", allDeviceList.size());

            // API返回的设备列表包含重复记录（type=1和type=4），需要去重
            Map<String, DeviceInfo> apiDataMap = allDeviceList.stream().filter(info -> info.getType() == 1)
                .collect(Collectors.toMap(DeviceInfo::getDeviceSn, Function.identity(), (k1, k2) -> k1));
            log.info("过滤type=1后有 {} 个逆变器设备", apiDataMap.size());

            // 2. 查询本地数据库中的逆变器设备
            QueryDevice queryDevice = new QueryDevice();
            queryDevice.setDeviceModel(DEV_MODEL_INVERTER);
            queryDevice.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> localDevices = deviceService.selectList(queryDevice);
            log.info("本地数据库有 {} 个逆变器设备", localDevices.size());

            if (CollectionUtils.isEmpty(localDevices)) {
                log.warn("本地数据库无逆变器设备");
                return;
            }

            // 3. 遍历本地设备，通过sn属性与API数据匹配
            for (EmsDevice device : localDevices) {
                try {
                    // 查询设备的sn属性
                    EmsObjAttrValue snAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_INVERTER,
                        device.getDeviceCode(), "sn");

                    if (snAttr == null || StringUtils.isBlank(snAttr.getAttrValue())) {
                        log.warn("逆变器设备 {} 无sn属性，跳过", device.getDeviceCode());
                        continue;
                    }

                    String sn = snAttr.getAttrValue();
                    DeviceInfo apiData = apiDataMap.get(sn);

                    if (apiData == null) {
                        log.warn("逆变器 {} (sn={}) 在API中未找到", device.getDeviceCode(), sn);
                        continue;
                    }

                    // 4. 更新设备属性
                    List<EmsObjAttrValue> existingAttrs = objAttrValueService.selectByObjCode(DEV_MODEL_INVERTER,
                        device.getDeviceCode());
                    Map<String, EmsObjAttrValue> attrMap = existingAttrs.stream()
                        .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity(), (k1, k2) -> k1));

                    // 更新或插入属性值
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_INVERTER, "manufacturer",
                        apiData.getManufacturer());
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_INVERTER, "model", apiData.getModel());
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_INVERTER, "type",
                        String.valueOf(apiData.getType()));
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_INVERTER, "status",
                        String.valueOf(apiData.getStatus()));
                    checkAndUpdate(attrMap, device.getDeviceCode(), DEV_MODEL_INVERTER, "lastUpdateTime",
                        apiData.getLastUpdateTime());

                    log.debug("逆变器 {} 属性已更新", device.getDeviceCode());

                }
                catch (Exception e) {
                    log.error("处理逆变器设备 {} 异常", device.getDeviceCode(), e);
                }
            }

            // 记录调用日志
            saveCallLog(SUBSYSTEM_CODE, SYS_MODEL_CODE, "SyncDevInverter", 0,
                "{\"plantList\":\"" + StringUtils.join(plantList, ",") + "\"}",
                "{\"count\":" + apiDataMap.size() + "}");

            log.info("逆变器列表数据同步完成");

        }
        catch (Exception e) {
            log.error("同步逆变器列表数据异常", e);
            saveCallLog(SUBSYSTEM_CODE, SYS_MODEL_CODE, "SyncDevInverter", -1,
                "{\"plantList\":\"" + StringUtils.join(config.getPlantList(), ",") + "\"}", e.getMessage());
        }
    }

    /**
     * 采集逆变器实时数据
     * 批量获取逆变器运行数据并更新到数据库
     */
    public void execCollectInverterData() {
        log.info("开始采集逆变器实时数据...");

        try {
            // 1. 查询本地逆变器设备
            QueryDevice queryDevice = new QueryDevice();
            queryDevice.setDeviceModel(DEV_MODEL_INVERTER);
            queryDevice.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> localDevices = deviceService.selectList(queryDevice);

            if (CollectionUtils.isEmpty(localDevices)) {
                log.warn("本地数据库无逆变器设备");
                return;
            }

            // 2. 获取所有逆变器的sn
            Set<String> snSet = new HashSet<>();
            Map<String, EmsDevice> snDeviceMap = new HashMap<>();

            for (EmsDevice device : localDevices) {
                EmsObjAttrValue snAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_INVERTER,
                    device.getDeviceCode(), "sn");
                if (snAttr != null && StringUtils.isNotBlank(snAttr.getAttrValue())) {
                    snSet.add(snAttr.getAttrValue());
                    snDeviceMap.put(snAttr.getAttrValue(), device);
                }
            }

            if (snSet.isEmpty()) {
                log.warn("没有可采集的逆变器sn");
                return;
            }

            log.info("准备采集 {} 个逆变器的实时数据", snSet.size());

            // 3. 调用API批量获取设备数据
            GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());
            List<String> snList = new ArrayList<>(snSet);
            JSONObject deviceDataJson = template.getDeviceData(INVERTER_TYPE_MAX, snList);

            if (deviceDataJson == null || deviceDataJson.isEmpty()) {
                log.warn("API返回设备数据为空");
                return;
            }

            log.info("从API获取到 {} 个设备的实时数据", deviceDataJson.size());

            // 4. 解析并更新每个设备的数据
            deviceDataJson.forEach((sn, dataObj) -> {
                EmsDevice device = snDeviceMap.get(sn);

                if (device != null) {
                    try {
                        JSONObject data = (JSONObject) dataObj;
                        updateInverterRuntimeData(device, data);
                        log.debug("逆变器 {} 实时数据已更新", device.getDeviceCode());
                    }
                    catch (Exception e) {
                        log.error("更新逆变器 {} 实时数据异常", device.getDeviceCode(), e);
                    }
                }
                else {
                    log.warn("sn={} 未找到对应设备", sn);
                }
            });

            // 记录调用日志
            saveCallLog(SUBSYSTEM_CODE, SYS_MODEL_CODE, "CollectInverterData", 0, "{\"snCount\":" + snSet.size() + "}",
                "{\"dataCount\":" + deviceDataJson.size() + "}");

            log.info("逆变器实时数据采集完成");

        }
        catch (Exception e) {
            log.error("采集逆变器实时数据异常", e);
            saveCallLog(SUBSYSTEM_CODE, SYS_MODEL_CODE, "CollectInverterData", -1, null, e.getMessage());
        }
    }

    /**
     * 更新逆变器运行时数据
     *
     * @param device 设备
     * @param data   API返回的数据
     */
    private void updateInverterRuntimeData(EmsDevice device, JSONObject data) {
        // 获取现有属性
        List<EmsObjAttrValue> existingAttrs = objAttrValueService.selectByObjCode(DEV_MODEL_INVERTER,
            device.getDeviceCode());
        Map<String, EmsObjAttrValue> attrMap = existingAttrs.stream()
            .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity()));

        String deviceCode = device.getDeviceCode();

        // 更新设备状态属性
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "statusText", data.getString("statusText"));

        // === 功率相关 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "pac", formatDouble(data.getDouble("pac")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "ppv", formatDouble(data.getDouble("ppv")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "ppv1", formatDouble(data.getDouble("ppv1")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "ppv2", formatDouble(data.getDouble("ppv2")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "ppv3", formatDouble(data.getDouble("ppv3")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "ppv4", formatDouble(data.getDouble("ppv4")));

        // === 电压相关 (PV输入电压) ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv1", formatDouble(data.getDouble("vpv1")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv2", formatDouble(data.getDouble("vpv2")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv3", formatDouble(data.getDouble("vpv3")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv4", formatDouble(data.getDouble("vpv4")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv5", formatDouble(data.getDouble("vpv5")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv6", formatDouble(data.getDouble("vpv6")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv7", formatDouble(data.getDouble("vpv7")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vpv8", formatDouble(data.getDouble("vpv8")));

        // === 组串电压 (vString) ===
        for (int i = 1; i <= 16; i++) {
            String key = "vString" + i;
            Double value = data.getDouble(key);
            if (value != null && value != 0.0) {
                checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, key, formatDouble(value));
            }
        }

        // === 母线电压 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "pBusVoltage",
            formatDouble(data.getDouble("pBusVoltage")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "nBusVoltage",
            formatDouble(data.getDouble("nBusVoltage")));

        // === 交流输出电压 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vacr", formatDouble(data.getDouble("vacr")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vacs", formatDouble(data.getDouble("vacs")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vact", formatDouble(data.getDouble("vact")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vacRs", formatDouble(data.getDouble("vacRs")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vacSt", formatDouble(data.getDouble("vacSt")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "vacTr", formatDouble(data.getDouble("vacTr")));

        // === 温度相关 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "temperature",
            formatDouble(data.getDouble("temperature")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "temperature2",
            formatDouble(data.getDouble("temperature2")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "temperature3",
            formatDouble(data.getDouble("temperature3")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "temperature5",
            formatDouble(data.getDouble("temperature5")));

        // === 发电量相关 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "eacToday", formatDouble(data.getDouble("eacToday")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "eacTotal", formatDouble(data.getDouble("eacTotal")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "epvTotal", formatDouble(data.getDouble("epvTotal")));

        // === 频率 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "fac", formatDouble(data.getDouble("fac")));

        // === 功率因数 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "pf", formatDouble(data.getDouble("pf")));

        // === 故障相关 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "faultCode1",
            String.valueOf(data.getIntValue("faultCode1")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "faultCode2",
            String.valueOf(data.getIntValue("faultCode2")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "faultType",
            String.valueOf(data.getIntValue("faultType")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "faultValue",
            String.valueOf(data.getIntValue("faultValue")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "warnCode",
            String.valueOf(data.getIntValue("warnCode")));

        // === 其他运行参数 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "deratingMode",
            String.valueOf(data.getIntValue("deratingMode")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "gfci", String.valueOf(data.getIntValue("gfci")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "pvIso", formatDouble(data.getDouble("pvIso")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "pidBus", formatDouble(data.getDouble("pidBus")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "opFullwatt",
            formatDouble(data.getDouble("opFullwatt")));
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "timeTotal", formatDouble(data.getDouble("timeTotal")));

        // === 更新时间 ===
        checkAndUpdate(attrMap, deviceCode, DEV_MODEL_INVERTER, "time", data.getString("time"));
    }

    /**
     * 格式化Double值，保留2位小数
     */
    private String formatDouble(Double value) {
        if (value == null) {
            return "0";
        }
        return String.format("%.2f", value);
    }

    /**
     * 同步单个采集器属性
     */
    private void execSyncCollectorAttr(String objCode) {
        log.info("同步采集器 {} 属性", objCode);

        try {
            // 获取设备sn
            EmsObjAttrValue snAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_COL, objCode, "sn");
            if (snAttr == null || StringUtils.isBlank(snAttr.getAttrValue())) {
                log.warn("采集器 {} 无sn属性", objCode);
                return;
            }

            GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());

            // 从所有电站获取采集器列表
            List<DataLogger> allDataLoggers = new ArrayList<>();
            List<String> plantList = config.getPlantList();
            for (String plantId : plantList) {
                List<DataLogger> dataLoggers = template.getDatalogList(plantId);
                if (CollectionUtils.isNotEmpty(dataLoggers)) {
                    allDataLoggers.addAll(dataLoggers);
                }
            }

            String sn = snAttr.getAttrValue();
            DataLogger target = allDataLoggers.stream().filter(d -> sn.equals(d.getSn())).findFirst().orElse(null);

            if (target == null) {
                log.warn("采集器 sn={} 在API中未找到", sn);
                return;
            }

            // 更新属性
            List<EmsObjAttrValue> existingAttrs = objAttrValueService.selectByObjCode(DEV_MODEL_COL, objCode);
            Map<String, EmsObjAttrValue> attrMap = existingAttrs.stream()
                .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity(), (k1, k2) -> k1));

            checkAndUpdate(attrMap, objCode, DEV_MODEL_COL, "manufacturer", target.getManufacturer());
            checkAndUpdate(attrMap, objCode, DEV_MODEL_COL, "model", target.getModel());
            checkAndUpdate(attrMap, objCode, DEV_MODEL_COL, "netMode", target.getNetMode());
            checkAndUpdate(attrMap, objCode, DEV_MODEL_COL, "type", String.valueOf(target.getType()));

            log.info("采集器 {} 属性同步完成", objCode);

        }
        catch (Exception e) {
            log.error("同步采集器 {} 属性异常", objCode, e);
        }
    }

    /**
     * 同步单个逆变器属性
     */
    private void execSyncInverterAttr(String objCode) {
        log.info("同步逆变器 {} 属性", objCode);

        try {
            // 获取设备sn
            EmsObjAttrValue snAttr = objAttrValueService.selectObjAttrValue(DEV_MODEL_INVERTER, objCode, "sn");
            if (snAttr == null || StringUtils.isBlank(snAttr.getAttrValue())) {
                log.warn("逆变器 {} 无sn属性", objCode);
                return;
            }

            String sn = snAttr.getAttrValue();

            // 调用API获取实时数据
            GrowattTemplate template = new GrowattTemplate(config.getUrl(), config.getToken());
            Map<String, Object> deviceDataMap = template.getDeviceData(INVERTER_TYPE_MAX,
                Collections.singletonList(sn));

            if (deviceDataMap == null || !deviceDataMap.containsKey(sn)) {
                log.warn("逆变器 sn={} 在API中未找到实时数据", sn);
                return;
            }

            // 查询设备
            QueryDevice query = new QueryDevice();
            query.setDeviceModel(DEV_MODEL_INVERTER);
            query.setDeviceCode(objCode);
            List<EmsDevice> devices = deviceService.selectList(query);

            if (CollectionUtils.isEmpty(devices)) {
                log.warn("逆变器设备 {} 不存在", objCode);
                return;
            }

            JSONObject data = (JSONObject) deviceDataMap.get(sn);
            updateInverterRuntimeData(devices.get(0), data);

            log.info("逆变器 {} 属性同步完成", objCode);

        }
        catch (Exception e) {
            log.error("同步逆变器 {} 属性异常", objCode, e);
        }
    }
}