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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hdkj.hussar.ApiResponse;
import com.hdkj.lt.bf.adapter.SiMeasurementClient;
import com.hdkj.lt.bf.common.SeMonitorThreshold;
import com.hdkj.lt.bf.common.SeSnapshotConstants;
import com.hdkj.lt.bf.entity.FhzgSeConsumerRelation;
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.mapper.FhzgSeConsumerRelationMapper;
import com.hdkj.lt.bf.mapper.FhzgSeMonitorVoltageMapper;
import com.hdkj.lt.bf.mapper.FhzgSeSnapshotDetailMapper;
import com.hdkj.lt.bf.mapper.FhzgSeVoltageEventMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

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

/**
 * 用户电压异步监测 Service V2
 *
 * @author lsl
 * @since 2026-07-23
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SeConsumerVoltageServiceImpl {

    private final FhzgSeConsumerRelationMapper consumerRelationMapper;
    private final FhzgSeSnapshotDetailMapper snapshotDetailMapper;
    private final FhzgSeMonitorVoltageMapper monitorVoltageMapper;
    private final FhzgSeVoltageEventMapper voltageEventMapper;
    private final SiMeasurementClient siMeasurementClient;

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

    @Async("seAsyncExecutor")
    @EventListener
    public void onMvtransOverVoltage(MvtransOverVoltageEvent event) {
        String mvtransId = event.getMvtransId();
        LocalDateTime snapTime = event.getSnapshotTime();
        log.info("配变电压越限，异步查用户电压 mvtransId={}, snapTime={}", mvtransId, snapTime);

        List<FhzgSeConsumerRelation> relations = consumerRelationMapper.selectList(
                new LambdaQueryWrapper<FhzgSeConsumerRelation>()
                        .eq(FhzgSeConsumerRelation::getMvtransId, mvtransId));
        if (relations == null || relations.isEmpty()) return;

        List<String> consNos = relations.stream()
                .map(FhzgSeConsumerRelation::getCustNo).filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (consNos.isEmpty()) return;
        Map<String, FhzgSeConsumerRelation> consNoMap = relations.stream()
                .filter(r -> r.getCustNo() != null)
                .collect(Collectors.toMap(FhzgSeConsumerRelation::getCustNo, r -> r, (a, b) -> a));

        String startTime = snapTime.minusMinutes(15).format(DT_FMT);
        String endTime = snapTime.format(DT_FMT);

        Map<String, Object> reqParam = new HashMap<>();
        reqParam.put("consNos", consNos);
        reqParam.put("startTime", startTime);
        reqParam.put("endTime", endTime);

        Map<String, BigDecimal> voltageMap;
        try {
            ApiResponse<Map<String, BigDecimal>> resp = siMeasurementClient.queryConsumerVoltage(reqParam);
            if (resp == null || resp.getData() == null) return;
            voltageMap = resp.getData();
        } catch (Exception e) {
            log.error("Feign调SI量测中心失败 mvtransId={}", mvtransId, e);
            return;
        }

        for (Map.Entry<String, BigDecimal> entry : voltageMap.entrySet()) {
            String consNo = entry.getKey();
            BigDecimal measValue = entry.getValue();
            FhzgSeConsumerRelation rel = consNoMap.get(consNo);
            if (rel == null || measValue == null) continue;

            BigDecimal baseV = SeMonitorThreshold.parseConsumerBaseVoltage(rel.getVoltageLevel());
            BigDecimal voltageRatio = measValue.divide(baseV, 4, RoundingMode.HALF_UP);
            int voltageStatus = calcConsumerVoltageStatus(voltageRatio);

            FhzgSeSnapshotDetail detail = FhzgSeSnapshotDetail.builder()
                    .snapshotTime(snapTime).deviceId(consNo).deviceType("consumer")
                    .consumerName(rel.getCustomerName())
                    .feederId(rel.getFeederId()).subsId(rel.getSubsId()).countyId(rel.getCountyId())
                    .mvtransId(mvtransId).consumerId(consNo)
                    .lvVoltageA(measValue).voltageRatio(voltageRatio).voltageStatus(voltageStatus)
                    .build();
            snapshotDetailMapper.insert(detail);

            upsertConsumerVoltageMonitor(consNo, "consumer",
                    rel.getFeederId(), rel.getSubsId(), rel.getCountyId(), mvtransId, consNo,
                    voltageRatio, voltageStatus, snapTime, rel);
        }
        log.info("配变{}用户电压处理完成 共{}户，成功{}户", mvtransId, consNos.size(), voltageMap.size());
    }

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

        if (state == null) {
            state = FhzgSeMonitorVoltage.builder()
                    .deviceId(deviceId).deviceType(deviceType)
                    .feederId(feederId).subsId(subsId).countyId(countyId)
                    .mvtransId(mvtransId).consumerId(consumerId)
                    .lastVoltageRatio(ratio).lastVoltageStatus(status)
                    .lastSnapTime(snapTime).alarmTriggered(0).build();
            if (isOverLimit) { state.setFirstOverTime(snapTime); }
            monitorVoltageMapper.insert(state);
        } else {
            LocalDateTime lastSnap = state.getLastSnapTime();
            boolean intervalExceeded = lastSnap != null
                    && Duration.between(lastSnap, snapTime).toMinutes() > SeMonitorThreshold.SNAP_INTERVAL_MINUTES;
            if (intervalExceeded) {
                // 断档间隙：先关掉还在活跃的事件，再清空状态机引用
                if (state.getAlarmTriggered() == 1 && state.getAlarmEventId() != null) {
                    FhzgSeVoltageEvent close = new FhzgSeVoltageEvent();
                    close.setId(state.getAlarmEventId());
                    close.setStatus(2);
                    close.setRecoverTime(snapTime);
                    close.setLastValue(ratio);
                    voltageEventMapper.updateById(close);
                }
                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 = resolveConsumerAlarmType(status);
                    BigDecimal threshold = resolveConsumerThreshold(status);
                    String countyName = lookupCountyName(countyId);

                    FhzgSeVoltageEvent event = FhzgSeVoltageEvent.builder()
                            .deviceId(deviceId).deviceName(rel != null ? rel.getCustomerName() : null)
                            .deviceType("consumer").alarmLevel("consumer").alarmType(alarmType)
                            .feederId(feederId).subsId(subsId).countyId(countyId).countyName(countyName)
                            .mvtransId(mvtransId).consumerId(consumerId)
                            .threshold(threshold)
                            .firstOverTime(state.getFirstOverTime())
                            .triggerTime(snapTime)
                            .triggerValue(ratio).lastValue(ratio)
                            .status(1).build();
                    voltageEventMapper.insert(event);
                    state.setAlarmTriggered(1);
                    state.setAlarmEventId(event.getId());
                }
            } else {
                if (state.getAlarmTriggered() == 1 && state.getAlarmEventId() != null) {
                    FhzgSeVoltageEvent update = new FhzgSeVoltageEvent();
                    update.setId(state.getAlarmEventId());
                    update.setStatus(2);
                    update.setRecoverTime(snapTime);
                    update.setLastValue(ratio);
                    voltageEventMapper.updateById(update);
                }
                state.setFirstOverTime(null);
                state.setAlarmTriggered(0);
                state.setAlarmEventId(null);
            }
            state.setLastVoltageRatio(ratio);
            state.setLastVoltageStatus(status);
            state.setLastSnapTime(snapTime);
            monitorVoltageMapper.updateById(state);
        }
    }

    /**
     * 计算用户电压越限状态
     * @return 0正常 1一般越上 2严重越上 3一般越下 4严重越下
     */
    private int calcConsumerVoltageStatus(BigDecimal ratio) {
        if (ratio == null || ratio.signum() <= 0) return 0;
        if (ratio.compareTo(SeMonitorThreshold.CONSUMER_SEVERE_V_OVER) > 0) return 2;
        if (ratio.compareTo(SeMonitorThreshold.CONSUMER_GENERAL_V_OVER) > 0) return 1;
        if (ratio.compareTo(SeMonitorThreshold.CONSUMER_SEVERE_V_UNDER) < 0) return 4;
        if (ratio.compareTo(SeMonitorThreshold.CONSUMER_GENERAL_V_UNDER) < 0) return 3;
        return 0;
    }

    /**
     * 查区县名称
     */
    private String lookupCountyName(String countyId) {
        if (countyId == null) return null;
        for (Map.Entry<String, String[]> entry : SeSnapshotConstants.COUNTIES) {
            if (countyId.equals(entry.getKey())) {
                return entry.getValue()[1];
            }
        }
        return null;
    }

    private String resolveConsumerAlarmType(int status) {
        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";
        }
    }

    private BigDecimal resolveConsumerThreshold(int status) {
        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;
        }
    }
}
