package com.hdkj.lt.bf.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hdkj.lt.bf.application.FeederGroupApplication;
import com.hdkj.lt.bf.common.SeMonitorThreshold;
import com.hdkj.lt.bf.entity.FhzgSeCurrentEvent;
import com.hdkj.lt.bf.entity.FhzgSeMonitorCurrent;
import com.hdkj.lt.bf.entity.FhzgSeMonitorVoltage;
import com.hdkj.lt.bf.entity.FhzgSeSnapshotDetail;
import com.hdkj.lt.bf.entity.FhzgSeVoltageEvent;
import com.hdkj.lt.bf.event.MvtransOverVoltageEvent;
import com.hdkj.lt.bf.event.ReconTriggerEvent;
import com.hdkj.lt.bf.mapper.FhzgSeCurrentEventMapper;
import com.hdkj.lt.bf.mapper.FhzgSeMonitorCurrentMapper;
import com.hdkj.lt.bf.mapper.FhzgSeMonitorVoltageMapper;
import com.hdkj.lt.bf.mapper.FhzgSeSnapshotDetailMapper;
import com.hdkj.lt.bf.mapper.FhzgSeVoltageEventMapper;
import com.hdkj.lt.bf.service.SeSnapshotService;
import com.hdkj.fhzg.optimization.response.FeederGroupTreeNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class SeSnapshotServiceImpl implements SeSnapshotService {

    private final FhzgSeSnapshotDetailMapper snapshotDetailMapper;
    private final FhzgSeMonitorCurrentMapper monitorCurrentMapper;
    private final FhzgSeMonitorVoltageMapper monitorVoltageMapper;
    private final FhzgSeCurrentEventMapper currentEventMapper;
    private final FhzgSeVoltageEventMapper voltageEventMapper;
    private final FeederGroupApplication feederGroupApplication;
    private final ApplicationEventPublisher eventPublisher;

    private static final DateTimeFormatter DT_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public void processSnapshots(String snapshotJsonArray) {
        JSONArray arr = JSON.parseArray(snapshotJsonArray);
        if (arr == null || arr.isEmpty()) return;
        for (int i = 0; i < arr.size(); i++) {
            processSnapshot(arr.getJSONObject(i).toJSONString());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processSnapshot(String snapshotJson) {
        JSONObject root = JSON.parseObject(snapshotJson);
        if (root == null) return;

        JSONArray pointTimes = root.getJSONArray("pointTime");
        if (pointTimes == null || pointTimes.isEmpty()) return;
        LocalDateTime snapTime = LocalDateTime.parse(pointTimes.getString(0), DT_FMT);

        Map<String, String[]> feederMap = buildFeederMapping();
        List<FhzgSeSnapshotDetail> batch = new ArrayList<>();

        // === 1. 馈线 ===
        JSONArray feeders = root.getJSONArray("periodFeederSeResult");
        if (feeders != null) {
            for (int i = 0; i < feeders.size(); i++) {
                JSONObject f = feeders.getJSONObject(i);
                FhzgSeSnapshotDetail d = parseFeeder(f, snapTime, feederMap);
                if (d != null) {
                    batch.add(d);
                    processFeederCurrent(f, d, snapTime, feederMap);
                    processFeederVoltage(f, d, snapTime, feederMap);
                }
            }
        }

        // === 2. 配变 ===
        JSONArray mvtrans = root.getJSONArray("periodMVTransSeResult");
        if (mvtrans != null) {
            for (int i = 0; i < mvtrans.size(); i++) {
                JSONObject m = mvtrans.getJSONObject(i);
                FhzgSeSnapshotDetail d = parseMvtrans(m, snapTime, feederMap);
                if (d != null) {
                    batch.add(d);
                    processMvtransMonitor(m, d, snapTime, feederMap);
                }
            }
        }

        if (!batch.isEmpty()) {
            // 防重：过滤掉该断面时刻已存在的 device_id
            Set<String> existingIds = new HashSet<>();
            snapshotDetailMapper.selectList(
                    new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
                            .select(FhzgSeSnapshotDetail::getDeviceId)
                            .eq(FhzgSeSnapshotDetail::getSnapshotTime, snapTime)
                            .in(FhzgSeSnapshotDetail::getDeviceId,
                                    batch.stream().map(FhzgSeSnapshotDetail::getDeviceId).collect(java.util.stream.Collectors.toList()))
            ).forEach(e -> existingIds.add(e.getDeviceId()));

            int inserted = 0;
            for (FhzgSeSnapshotDetail d : batch) {
                if (existingIds.contains(d.getDeviceId())) continue;
                snapshotDetailMapper.insert(d);
                inserted++;
            }
            log.info("状估断面处理完成 snapTime={}, 写入{}条(去重跳过{}条)",
                    snapTime, inserted, batch.size() - inserted);
        }
    }

    // ============================================================
    // 馈线
    // ============================================================

    private FhzgSeSnapshotDetail parseFeeder(JSONObject f, LocalDateTime snapTime, Map<String, String[]> feederMap) {
        String feederId = f.getString("psrId");
        String[] loc = feederMap.getOrDefault(feederId, new String[]{"", "", ""});
        BigDecimal loadRate = firstValue(f.getJSONArray("loadRates"));
        BigDecimal voltage = firstValue(f.getJSONArray("seoUs"));
        BigDecimal voltageRatio = voltage != null
                ? voltage.divide(SeMonitorThreshold.FEEDER_BASE_KV, 4, RoundingMode.HALF_UP) : null;
        return FhzgSeSnapshotDetail.builder()
                .snapshotTime(snapTime).deviceId(feederId).deviceType("feeder")
                .feederId(feederId).feederName(loc.length > 2 ? loc[2] : null)
                .subsId(loc[0]).countyId(loc[1])
                .activePower(firstValue(f.getJSONArray("seoPs")))
                .reactivePower(firstValue(f.getJSONArray("seoQs")))
                .currentValue(firstValue(f.getJSONArray("seoIs")))
                .voltageValue(voltage).loadRate(loadRate).voltageRatio(voltageRatio)
                .currentStatus(calcCurrentStatus(loadRate))
                .voltageStatus(calcFeederVoltageStatus(voltageRatio))
                .build();
    }

    private void processFeederCurrent(JSONObject f, FhzgSeSnapshotDetail detail,
                                       LocalDateTime snapTime, Map<String, String[]> feederMap) {
        if (detail.getCurrentStatus() == null) return;
        String feederId = detail.getFeederId();
        String[] loc = feederMap.get(feederId);
        String feederName = loc != null && loc.length > 2 ? loc[2] : null;
        String countyId = loc != null ? loc[1] : "";
        String subsId = loc != null ? loc[0] : "";
        BigDecimal loadRate = detail.getLoadRate();
        int status = detail.getCurrentStatus();
        boolean isOverLimit = status != 0;

        FhzgSeMonitorCurrent state = monitorCurrentMapper.selectOne(
                new LambdaQueryWrapper<FhzgSeMonitorCurrent>()
                        .eq(FhzgSeMonitorCurrent::getFeederId, feederId).last("LIMIT 1"));

        if (state == null) {
            state = FhzgSeMonitorCurrent.builder()
                    .feederId(feederId).feederName(feederName)
                    .lastLoadRate(loadRate).lastStatus(status).lastSnapTime(snapTime)
                    .alarmTriggered(0).build();
            if (isOverLimit) state.setFirstOverTime(snapTime);
            monitorCurrentMapper.insert(state);
        } else {
            LocalDateTime lastSnap = state.getLastSnapTime();
            if (lastSnap != null && Duration.between(lastSnap, snapTime).toMinutes() > SeMonitorThreshold.SNAP_INTERVAL_MINUTES) {
                state.setFirstOverTime(null);
                state.setAlarmTriggered(0);
                state.setAlarmEventId(null);
            }
            BigDecimal maxLoadRate = state.getLastLoadRate();
            if (loadRate != null && (maxLoadRate == null || loadRate.compareTo(maxLoadRate) > 0))
                maxLoadRate = loadRate;

            if (isOverLimit) {
                if (state.getFirstOverTime() == null) state.setFirstOverTime(snapTime);
                if (state.getFirstOverTime() != null
                        && Duration.between(state.getFirstOverTime(), snapTime).toMinutes() >= SeMonitorThreshold.TRIGGER_DURATION_MINUTES
                        && state.getAlarmTriggered() == 0) {
                    // 触发时往回看1小时窗口：有任意断面≥100%算过载，否则重载
                    boolean hasOverload = hasOverloadSnapshotInWindow(feederId, state.getFirstOverTime(), snapTime);
                    String alarmType = hasOverload ? "current_overload" : "current_heavy";
                    String countyName = lookupCountyName(countyId, feederMap);
                    FhzgSeCurrentEvent event = FhzgSeCurrentEvent.builder()
                            .feederId(feederId).feederName(feederName).alarmType(alarmType)
                            .countyId(countyId).countyName(countyName).subsId(subsId)
                            .firstOverTime(state.getFirstOverTime()).triggerTime(snapTime)
                            .triggerLoadRate(loadRate).maxLoadRate(maxLoadRate).lastLoadRate(loadRate).status(1)
                            .build();
                    currentEventMapper.insert(event);
                    state.setAlarmTriggered(1);
                    state.setAlarmEventId(event.getId());
                    // 异步触发重构算法（需要 feeder_id + point_time）
                    eventPublisher.publishEvent(new ReconTriggerEvent(
                            event.getId(), feederId, feederName, countyId, subsId,
                            alarmType, snapTime, state.getFirstOverTime()));
                }
            } else {
                if (state.getAlarmTriggered() == 1 && state.getAlarmEventId() != null) {
                    FhzgSeCurrentEvent update = new FhzgSeCurrentEvent();
                    update.setId(state.getAlarmEventId());
                    update.setStatus(2); update.setRecoverTime(snapTime);
                    update.setLastLoadRate(loadRate); update.setMaxLoadRate(maxLoadRate);
                    currentEventMapper.updateById(update);
                }
                state.setFirstOverTime(null); state.setAlarmTriggered(0); state.setAlarmEventId(null);
            }
            state.setLastLoadRate(loadRate); state.setLastStatus(status); state.setLastSnapTime(snapTime);
            monitorCurrentMapper.updateById(state);
        }
    }

    private void processFeederVoltage(JSONObject f, FhzgSeSnapshotDetail detail,
                                       LocalDateTime snapTime, Map<String, String[]> feederMap) {
        if (detail.getVoltageStatus() == null) return;
        String[] loc = feederMap.get(detail.getFeederId());
        checkVoltageMonitor(detail.getFeederId(), "feeder", detail.getVoltageRatio(), detail.getVoltageStatus(),
                snapTime, detail.getFeederId(), loc != null && loc.length > 2 ? loc[2] : null,
                loc != null ? loc[0] : "", loc != null ? loc[1] : "", null, null);
    }

    // ============================================================
    // 配变
    // ============================================================

    private FhzgSeSnapshotDetail parseMvtrans(JSONObject m, LocalDateTime snapTime, Map<String, String[]> feederMap) {
        String mvtransId = m.getString("psrId");
        String feederId = m.getString("feederId");
        String[] loc = feederMap.getOrDefault(feederId, new String[]{"", "", ""});
        BigDecimal lvVoltageA = firstValue(m.getJSONArray("seiLvUas"));
        BigDecimal voltageRatio = lvVoltageA != null
                ? lvVoltageA.divide(SeMonitorThreshold.MVTRANS_BASE_KV, 4, RoundingMode.HALF_UP) : null;
        BigDecimal capacity = null;
        String capStr = m.getString("capacitys");
        if (capStr != null) { try { capacity = new BigDecimal(capStr); } catch (NumberFormatException ignored) {} }
        return FhzgSeSnapshotDetail.builder()
                .snapshotTime(snapTime).deviceId(mvtransId).deviceType("mvtrans")
                .feederId(feederId).subsId(loc[0]).countyId(loc[1])
                .lvVoltageA(lvVoltageA).capacity(capacity).voltageRatio(voltageRatio)
                .voltageStatus(calcMvtransVoltageStatus(voltageRatio))
                .build();
    }

    private void processMvtransMonitor(JSONObject m, FhzgSeSnapshotDetail detail,
                                        LocalDateTime snapTime, Map<String, String[]> feederMap) {
        if (detail.getVoltageStatus() == null) return;
        String mvtransId = detail.getDeviceId();
        String[] loc = feederMap.get(detail.getFeederId());
        int status = detail.getVoltageStatus();
        if (status == 0) recoverUserAlarms(mvtransId, snapTime);

        checkVoltageMonitor(mvtransId, "mvtrans", detail.getVoltageRatio(), status,
                snapTime, detail.getFeederId(), loc != null && loc.length > 2 ? loc[2] : null,
                loc != null ? loc[0] : "", loc != null ? loc[1] : "", mvtransId, null);

        if (status != 0) {
            eventPublisher.publishEvent(new MvtransOverVoltageEvent(
                    this, mvtransId, detail.getFeederId(),
                    loc != null ? loc[1] : "", loc != null ? loc[0] : "",
                    snapTime, detail.getVoltageRatio()));
        }
    }

    // ============================================================
    // 电压状态机
    // ============================================================

    private void checkVoltageMonitor(String deviceId, String deviceType,
                                      BigDecimal voltageRatio, int voltageStatus,
                                      LocalDateTime snapTime, String feederId, String feederName,
                                      String subsId, String countyId, String mvtransId, String consumerId) {
        FhzgSeMonitorVoltage state = monitorVoltageMapper.selectOne(
                new LambdaQueryWrapper<FhzgSeMonitorVoltage>()
                        .eq(FhzgSeMonitorVoltage::getDeviceId, deviceId)
                        .eq(FhzgSeMonitorVoltage::getDeviceType, deviceType).last("LIMIT 1"));
        boolean isOverLimit = voltageStatus != 0;

        if (state == null) {
            state = FhzgSeMonitorVoltage.builder()
                    .deviceId(deviceId).deviceType(deviceType)
                    .feederId(feederId).feederName(feederName)
                    .subsId(subsId).countyId(countyId)
                    .mvtransId(mvtransId).consumerId(consumerId)
                    .lastVoltageRatio(voltageRatio).lastVoltageStatus(voltageStatus)
                    .lastSnapTime(snapTime).alarmTriggered(0).build();
            if (isOverLimit) state.setFirstOverTime(snapTime);
            monitorVoltageMapper.insert(state);
        } else {
            LocalDateTime lastSnap = state.getLastSnapTime();
            if (lastSnap != null && Duration.between(lastSnap, snapTime).toMinutes() > SeMonitorThreshold.SNAP_INTERVAL_MINUTES) {
                state.setFirstOverTime(null); state.setAlarmTriggered(0); state.setAlarmEventId(null);
            }
            if (isOverLimit) {
                if (state.getFirstOverTime() == null) state.setFirstOverTime(snapTime);
                if (state.getFirstOverTime() != null
                        && Duration.between(state.getFirstOverTime(), snapTime).toMinutes() >= SeMonitorThreshold.TRIGGER_DURATION_MINUTES
                        && state.getAlarmTriggered() == 0) {
                    String alarmType = resolveVoltageAlarmType(deviceType, voltageStatus);
                    String countyName = lookupCountyName(countyId, null);
                    BigDecimal threshold = resolveVoltageThreshold(deviceType, voltageStatus);
                    BigDecimal rangeMax = null, rangeMin = null;
                    int overUpper = 0, overLower = 0;
                    if ("feeder".equals(deviceType) && feederId != null) {
                        BigDecimal[] vr = queryVoltageRangeFromSnap(feederId, state.getFirstOverTime(), snapTime);
                        rangeMax = vr[0]; rangeMin = vr[1];
                        int[] mc = queryMvtransCounts(feederId, state.getFirstOverTime(), snapTime);
                        overUpper = mc[0]; overLower = mc[1];
                    }
                    FhzgSeVoltageEvent event = FhzgSeVoltageEvent.builder()
                            .deviceId(deviceId).deviceName(feederName)
                            .deviceType(deviceType).alarmLevel(deviceType).alarmType(alarmType)
                            .feederId(feederId).feederName(feederName)
                            .subsId(subsId).countyId(countyId).countyName(countyName)
                            .mvtransId(mvtransId).consumerId(consumerId).threshold(threshold)
                            .firstOverTime(state.getFirstOverTime()).triggerTime(snapTime)
                            .triggerValue(voltageRatio)
                            .voltageRangeMax(rangeMax).voltageRangeMin(rangeMin)
                            .overUpperMvtrans(overUpper).overLowerMvtrans(overLower)
                            .lastValue(voltageRatio).status(1).build();
                    voltageEventMapper.insert(event);
                    state.setAlarmTriggered(1); state.setAlarmEventId(event.getId());
                    // 馈线越下限 → 异步触发重构算法
                    if ("feeder".equals(deviceType) && "voltage_under".equals(alarmType)) {
                        eventPublisher.publishEvent(new ReconTriggerEvent(
                                event.getId(), feederId, feederName, countyId, subsId,
                                alarmType, snapTime, state.getFirstOverTime()));
                    }
                }
            } else {
                if (state.getAlarmTriggered() == 1 && state.getAlarmEventId() != null) {
                    FhzgSeVoltageEvent update = new FhzgSeVoltageEvent();
                    update.setId(state.getAlarmEventId());
                    update.setStatus(2); update.setRecoverTime(snapTime); update.setLastValue(voltageRatio);
                    voltageEventMapper.updateById(update);
                }
                state.setFirstOverTime(null); state.setAlarmTriggered(0); state.setAlarmEventId(null);
            }
            state.setLastVoltageRatio(voltageRatio); state.setLastVoltageStatus(voltageStatus);
            state.setLastSnapTime(snapTime);
            monitorVoltageMapper.updateById(state);
        }
    }

    // ============================================================
    // 配变→用户恢复
    // ============================================================

    private void recoverUserAlarms(String mvtransId, LocalDateTime snapTime) {
        FhzgSeVoltageEvent updateEvent = new FhzgSeVoltageEvent();
        updateEvent.setStatus(2); updateEvent.setRecoverTime(snapTime);
        voltageEventMapper.update(updateEvent,
                new LambdaQueryWrapper<FhzgSeVoltageEvent>()
                        .eq(FhzgSeVoltageEvent::getMvtransId, mvtransId)
                        .eq(FhzgSeVoltageEvent::getAlarmLevel, "consumer")
                        .eq(FhzgSeVoltageEvent::getStatus, 1));
        FhzgSeMonitorVoltage reset = new FhzgSeMonitorVoltage();
        reset.setFirstOverTime(null); reset.setAlarmTriggered(0);
        reset.setAlarmEventId(null); reset.setLastVoltageStatus(0);
        monitorVoltageMapper.update(reset,
                new LambdaQueryWrapper<FhzgSeMonitorVoltage>()
                        .eq(FhzgSeMonitorVoltage::getMvtransId, mvtransId)
                        .eq(FhzgSeMonitorVoltage::getDeviceType, "consumer"));
    }

    // ============================================================
    // 查询辅助
    // ============================================================

    private BigDecimal[] queryVoltageRangeFromSnap(String feederId, LocalDateTime start, LocalDateTime end) {
        List<FhzgSeSnapshotDetail> list = snapshotDetailMapper.selectList(
                new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
                        .eq(FhzgSeSnapshotDetail::getFeederId, feederId)
                        .eq(FhzgSeSnapshotDetail::getDeviceType, "feeder")
                        .isNotNull(FhzgSeSnapshotDetail::getVoltageRatio)
                        .ge(FhzgSeSnapshotDetail::getSnapshotTime, start)
                        .le(FhzgSeSnapshotDetail::getSnapshotTime, end));
        BigDecimal maxV = null, minV = null;
        for (FhzgSeSnapshotDetail s : list) {
            BigDecimal v = s.getVoltageRatio();
            if (v == null) continue;
            if (maxV == null || v.compareTo(maxV) > 0) maxV = v;
            if (minV == null || v.compareTo(minV) < 0) minV = v;
        }
        return new BigDecimal[]{maxV, minV};
    }

    private int[] queryMvtransCounts(String feederId, LocalDateTime start, LocalDateTime end) {
        List<FhzgSeVoltageEvent> list = voltageEventMapper.selectList(
                new LambdaQueryWrapper<FhzgSeVoltageEvent>()
                        .eq(FhzgSeVoltageEvent::getFeederId, feederId)
                        .eq(FhzgSeVoltageEvent::getAlarmLevel, "mvtrans")
                        .eq(FhzgSeVoltageEvent::getStatus, 1)
                        .ge(FhzgSeVoltageEvent::getFirstOverTime, start)
                        .le(FhzgSeVoltageEvent::getFirstOverTime, end));
        int up = 0, down = 0;
        for (FhzgSeVoltageEvent e : list) {
            if (e.getAlarmType() != null && e.getAlarmType().contains("over")) up++;
            else if (e.getAlarmType() != null && e.getAlarmType().contains("under")) down++;
        }
        return new int[]{up, down};
    }

    /**
     * 查窗口内是否有任意过载断面(≥100%)
     */
    private boolean hasOverloadSnapshotInWindow(String feederId, LocalDateTime start, LocalDateTime end) {
        Long count = snapshotDetailMapper.selectCount(
                new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
                        .eq(FhzgSeSnapshotDetail::getFeederId, feederId)
                        .eq(FhzgSeSnapshotDetail::getDeviceType, "feeder")
                        .ge(FhzgSeSnapshotDetail::getLoadRate, SeMonitorThreshold.LOAD_RATE_OVERLOAD)
                        .ge(FhzgSeSnapshotDetail::getSnapshotTime, start)
                        .le(FhzgSeSnapshotDetail::getSnapshotTime, end));
        return count != null && count > 0;
    }

    // ============================================================
    // 状态判断 / 阈值
    // ============================================================

    private int calcCurrentStatus(BigDecimal loadRate) {
        if (loadRate == null) return 0;
        if (loadRate.compareTo(SeMonitorThreshold.LOAD_RATE_OVERLOAD) >= 0) return 2;
        if (loadRate.compareTo(SeMonitorThreshold.LOAD_RATE_HEAVY) >= 0) return 1;
        return 0;
    }

    private int calcFeederVoltageStatus(BigDecimal ratio) {
        if (ratio == null) return 0;
        if (ratio.compareTo(SeMonitorThreshold.FEEDER_V_OVER) > 0) return 1;
        if (ratio.compareTo(SeMonitorThreshold.FEEDER_V_UNDER) < 0) return 2;
        return 0;
    }

    private int calcMvtransVoltageStatus(BigDecimal ratio) {
        if (ratio == null) return 0;
        if (ratio.compareTo(SeMonitorThreshold.MVTRANS_V_OVER) > 0) return 1;
        if (ratio.compareTo(SeMonitorThreshold.MVTRANS_V_UNDER) < 0) return 2;
        return 0;
    }

    private String resolveVoltageAlarmType(String deviceType, int status) {
        if ("consumer".equals(deviceType)) {
            switch (status) {
                case 1: return "voltage_over_general";
                case 2: return "voltage_over_severe";
                case 3: return "voltage_under_general";
                case 4: return "voltage_under_severe";
                default: return "voltage_over";
            }
        }
        return status == 1 ? "voltage_over" : "voltage_under";
    }

    private BigDecimal resolveVoltageThreshold(String deviceType, int status) {
        if ("feeder".equals(deviceType)) return status == 1 ? SeMonitorThreshold.FEEDER_V_OVER : SeMonitorThreshold.FEEDER_V_UNDER;
        if ("mvtrans".equals(deviceType)) return status == 1 ? SeMonitorThreshold.MVTRANS_V_OVER : SeMonitorThreshold.MVTRANS_V_UNDER;
        switch (status) {
            case 1: return SeMonitorThreshold.CONSUMER_GENERAL_V_OVER;
            case 2: return SeMonitorThreshold.CONSUMER_SEVERE_V_OVER;
            case 3: return SeMonitorThreshold.CONSUMER_GENERAL_V_UNDER;
            case 4: return SeMonitorThreshold.CONSUMER_SEVERE_V_UNDER;
            default: return null;
        }
    }

    // ============================================================
    // 辅助
    // ============================================================

    private BigDecimal firstValue(JSONArray arr) {
        if (arr == null || arr.isEmpty()) return null;
        String v = arr.getString(0);
        if (v == null || v.isEmpty()) return null;
        try { return new BigDecimal(v); } catch (NumberFormatException e) { return null; }
    }

    private String lookupCountyName(String countyId, Map<String, String[]> feederMap) {
        return null;
    }

    private Map<String, String[]> buildFeederMapping() {
        Map<String, String[]> map = new HashMap<>();
        try {
            List<FeederGroupTreeNode> tree = feederGroupApplication.getFeederGroupTree();
            if (tree != null) buildFeederMappingRecursive(tree, map, "", "");
        } catch (Exception e) {
            log.warn("构建馈线映射失败", e);
        }
        return map;
    }

    private void buildFeederMappingRecursive(List<FeederGroupTreeNode> nodes, Map<String, String[]> map,
                                              String parentSubsId, String parentCountyId) {
        if (nodes == null) return;
        for (FeederGroupTreeNode node : nodes) {
            String subsId = parentSubsId, countyId = parentCountyId;
            if (node.getType() == 2) countyId = node.getId();
            else if (node.getType() == 3) subsId = node.getId();
            else if (node.getType() == 4) map.put(node.getId(), new String[]{subsId, countyId, node.getName()});
            if (node.getChildren() != null && !node.getChildren().isEmpty())
                buildFeederMappingRecursive(node.getChildren(), map, subsId, countyId);
        }
    }
}