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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.FhzgSeVoltageEvent;
import com.hdkj.lt.bf.application.FeederGroupApplication;
import com.hdkj.lt.bf.entity.vo.*;
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.FhzgSeVoltageEventMapper;
import com.hdkj.lt.bf.service.SeAlarmService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 异常告警查询 Service 实现 V2
 *
 * @author lsl
 * @since 2026-07-23
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SeAlarmServiceImpl implements SeAlarmService {

    private final FhzgSeCurrentEventMapper currentEventMapper;
    private final FhzgSeVoltageEventMapper voltageEventMapper;
    private final FeederGroupApplication feederGroupApplication;
    private final FhzgSeMonitorCurrentMapper monitorCurrentMapper;
    private final FhzgSeMonitorVoltageMapper monitorVoltageMapper;

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

    private static final List<String> OVERLOAD_TYPES = Arrays.asList("current_heavy", "current_overload");
    private static final List<String> VOLTAGE_TYPES = Arrays.asList(
            "voltage_over", "voltage_under", "voltage_over_general", "voltage_over_severe",
            "voltage_under_general", "voltage_under_severe");

    // ============================================================
    // 1. 重过载列表
    // ============================================================

    @Override
    public PageResult<SeAlarmListVO> queryOverloadAlarmList(String id, Integer type, String feederName,
                                                             String date, String orderDir,
                                                             Integer page, Integer pageSize) {
        if (page == null || page < 1) page = 1;
        if (pageSize == null || pageSize < 1) pageSize = 20;

        LocalDate queryDate = parseDate(date);
        LocalDateTime dayStart = queryDate.atStartOfDay();
        LocalDateTime dayEnd = queryDate.plusDays(1).atStartOfDay();

        Page<FhzgSeCurrentEvent> mpPage = new Page<>(page, pageSize);

        LambdaQueryWrapper<FhzgSeCurrentEvent> wrapper = new LambdaQueryWrapper<FhzgSeCurrentEvent>()
                .ge(FhzgSeCurrentEvent::getFirstOverTime, dayStart)
                .lt(FhzgSeCurrentEvent::getFirstOverTime, dayEnd)
                .eq(FhzgSeCurrentEvent::getStatus, 1)
                .in(FhzgSeCurrentEvent::getAlarmType, OVERLOAD_TYPES);

        applyCurrentFilter(wrapper, id, type);
        if (StringUtils.isNotBlank(feederName)) {
            wrapper.like(FhzgSeCurrentEvent::getFeederName, feederName);
        }
        applyOrderBy(wrapper, orderDir, FhzgSeCurrentEvent::getFirstOverTime);

        Page<FhzgSeCurrentEvent> result = currentEventMapper.selectPage(mpPage, wrapper);
        List<SeAlarmListVO> voList = result.getRecords().stream().map(this::toOverloadVO).collect(Collectors.toList());
        return PageResult.of(result, voList);
    }

    private SeAlarmListVO toOverloadVO(FhzgSeCurrentEvent e) {
        String displayValue = e.getLastLoadRate() != null
                ? e.getLastLoadRate().setScale(0, java.math.RoundingMode.HALF_UP).toPlainString()
                : "80";
        return SeAlarmListVO.builder()
                .alarmEventId(e.getId())
                .feederName(e.getFeederName())
                .feederId(e.getFeederId())
                .alarmDisplayValue(displayValue)
                .alarmTime(e.getFirstOverTime() != null ? e.getFirstOverTime().format(DT_FMT) : null)
                .alarmType(e.getAlarmType())
                .alarmLevel("feeder")
                .build();
    }

    // ============================================================
    // 2. 电压越限列表
    // ============================================================

    @Override
    public PageResult<SeAlarmListVO> queryVoltageAlarmList(String id, Integer type, String feederName,
                                                            String date, String orderDir,
                                                            Integer page, Integer pageSize) {
        if (page == null || page < 1) page = 1;
        if (pageSize == null || pageSize < 1) pageSize = 20;

        LocalDate queryDate = parseDate(date);
        LocalDateTime dayStart = queryDate.atStartOfDay();
        LocalDateTime dayEnd = queryDate.plusDays(1).atStartOfDay();

        Page<FhzgSeVoltageEvent> mpPage = new Page<>(page, pageSize);

        LambdaQueryWrapper<FhzgSeVoltageEvent> wrapper = new LambdaQueryWrapper<FhzgSeVoltageEvent>()
                .ge(FhzgSeVoltageEvent::getFirstOverTime, dayStart)
                .lt(FhzgSeVoltageEvent::getFirstOverTime, dayEnd)
                .eq(FhzgSeVoltageEvent::getStatus, 1)
                .in(FhzgSeVoltageEvent::getAlarmLevel, "feeder", "mvtrans");

        applyVoltageFilter(wrapper, id, type);
        if (StringUtils.isNotBlank(feederName)) {
            wrapper.like(FhzgSeVoltageEvent::getFeederName, feederName);
        }
        applyOrderBy(wrapper, orderDir, FhzgSeVoltageEvent::getFirstOverTime);

        Page<FhzgSeVoltageEvent> result = voltageEventMapper.selectPage(mpPage, wrapper);
        List<SeAlarmListVO> voList = result.getRecords().stream().map(this::toVoltageVO).collect(Collectors.toList());
        return PageResult.of(result, voList);
    }

    private SeAlarmListVO toVoltageVO(FhzgSeVoltageEvent e) {
        String displayValue = resolveVoltageDisplay(e.getAlarmType(), e.getAlarmLevel());
        String feederName = e.getDeviceName();
        // 台区告警时显示馈线名称
        if ("mvtrans".equals(e.getAlarmLevel())) {
            feederName = e.getFeederName();
        }
        return SeAlarmListVO.builder()
                .alarmEventId(e.getId())
                .feederName(feederName)
                .feederId(e.getFeederId())
                .alarmDisplayValue(displayValue)
                .alarmTime(e.getFirstOverTime() != null ? e.getFirstOverTime().format(DT_FMT) : null)
                .alarmType(e.getAlarmType())
                .alarmLevel(e.getAlarmLevel())
                .build();
    }

    private String resolveVoltageDisplay(String alarmType, String alarmLevel) {
        boolean isMvtrans = "mvtrans".equals(alarmLevel);
        String prefix = isMvtrans ? "台区" : "线路";
        if (alarmType != null && alarmType.contains("over")) return prefix + "电压越上限";
        if (alarmType != null && alarmType.contains("under")) return prefix + "电压越下限";
        return prefix + "电压越限";
    }

    // ============================================================
    // 3. 运行异常信息详情
    // ============================================================

    @Override
    public SeAlarmDetailVO queryAlarmDetail(Long alarmEventId) {
        if (alarmEventId == null) return null;

        // 先查重过载事件
        FhzgSeCurrentEvent currentEvent = currentEventMapper.selectById(alarmEventId);
        if (currentEvent != null) {
            return buildOverloadDetail(currentEvent);
        }

        // 再查电压越限事件
        FhzgSeVoltageEvent voltageEvent = voltageEventMapper.selectById(alarmEventId);
        if (voltageEvent != null) {
            return buildVoltageDetail(voltageEvent);
        }

        return null;
    }

    private SeAlarmDetailVO buildOverloadDetail(FhzgSeCurrentEvent event) {
        // 告警结束时间
        LocalDateTime endTime = event.getRecoverTime();
        if (endTime == null && event.getStatus() == 1) {
            FhzgSeMonitorCurrent state = monitorCurrentMapper.selectOne(
                    new LambdaQueryWrapper<FhzgSeMonitorCurrent>()
                            .eq(FhzgSeMonitorCurrent::getFeederId, event.getFeederId())
                            .last("LIMIT 1"));
            if (state != null) endTime = state.getLastSnapTime();
        }
        if (endTime == null) endTime = event.getTriggerTime();

        return SeAlarmDetailVO.builder()
                .alarmEventId(event.getId())
                .alarmType(event.getAlarmType())
                .alarmCategory("overload")
                .countyName(event.getCountyName())
                .feederName(event.getFeederName())
                .alarmStartTime(event.getFirstOverTime())
                .alarmEndTime(endTime)
                .maxLoadRate(event.getMaxLoadRate())
                .reconStatus(event.getReconStatus())
                .build();
    }

    private SeAlarmDetailVO buildVoltageDetail(FhzgSeVoltageEvent event) {
        String indicator = resolveVoltageDisplay(event.getAlarmType(), event.getAlarmLevel());
        String feederName = event.getFeederName();

        LocalDateTime endTime = event.getRecoverTime();
        if (endTime == null && event.getStatus() == 1) {
            FhzgSeMonitorVoltage state = monitorVoltageMapper.selectOne(
                    new LambdaQueryWrapper<FhzgSeMonitorVoltage>()
                            .eq(FhzgSeMonitorVoltage::getDeviceId, event.getDeviceId())
                            .eq(FhzgSeMonitorVoltage::getDeviceType, event.getDeviceType())
                            .last("LIMIT 1"));
            if (state != null) endTime = state.getLastSnapTime();
        }
        if (endTime == null) endTime = event.getTriggerTime();

        return SeAlarmDetailVO.builder()
                .alarmEventId(event.getId())
                .alarmType(event.getAlarmType())
                .alarmCategory("voltage")
                .countyName(event.getCountyName())
                .feederName(feederName)
                .alarmStartTime(event.getFirstOverTime())
                .alarmEndTime(endTime)
                .abnormalIndicator(indicator)
                .maxVoltage(event.getVoltageRangeMax())
                .minVoltage(event.getVoltageRangeMin())
                .overUpperMvtransCount(event.getOverUpperMvtrans())
                .overLowerMvtransCount(event.getOverLowerMvtrans())
                .reconStatus(event.getReconStatus())
                .build();
    }

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

    private void applyCurrentFilter(LambdaQueryWrapper<FhzgSeCurrentEvent> wrapper, String id, Integer type) {
        if (type == 2) wrapper.eq(FhzgSeCurrentEvent::getCountyId, id);
        else if (type == 3) wrapper.eq(FhzgSeCurrentEvent::getSubsId, id);
        else if (type == 4) wrapper.eq(FhzgSeCurrentEvent::getFeederId, id);
    }

    private void applyVoltageFilter(LambdaQueryWrapper<FhzgSeVoltageEvent> wrapper, String id, Integer type) {
        if (type == 2) wrapper.eq(FhzgSeVoltageEvent::getCountyId, id);
        else if (type == 3) wrapper.eq(FhzgSeVoltageEvent::getSubsId, id);
        else if (type == 4) wrapper.eq(FhzgSeVoltageEvent::getFeederId, id);
    }

    // ============================================================
    // 线路下拉列表
    // ============================================================

    @Override
    public List<FeederSelectVO> queryFeederList(String id, Integer type) {
        List<FeederSelectVO> result = new java.util.ArrayList<>();
        if (id == null || type == null) return result;

        try {
            java.util.List<com.hdkj.fhzg.optimization.response.FeederGroupTreeNode> tree = feederGroupApplication.getFeederGroupTree();
            if (tree == null) return result;

            // 找到目标节点
            com.hdkj.fhzg.optimization.response.FeederGroupTreeNode target = findNode(tree, id, type);
            if (target == null) return result;

            // 收集其下所有 type=4 的馈线
            collectFeeders(target, result);
        } catch (Exception e) {
            log.warn("查询线路下拉列表失败 id={}, type={}", id, type, e);
        }
        return result;
    }

    private com.hdkj.fhzg.optimization.response.FeederGroupTreeNode findNode(
            java.util.List<com.hdkj.fhzg.optimization.response.FeederGroupTreeNode> nodes,
            String id, Integer type) {
        if (nodes == null) return null;
        for (com.hdkj.fhzg.optimization.response.FeederGroupTreeNode node : nodes) {
            if (type.equals(node.getType()) && id.equals(node.getId())) {
                return node;
            }
            if (node.getChildren() != null && !node.getChildren().isEmpty()) {
                com.hdkj.fhzg.optimization.response.FeederGroupTreeNode found = findNode(node.getChildren(), id, type);
                if (found != null) return found;
            }
        }
        return null;
    }

    // ============================================================
    // 辅助：日期解析 + 排序
    // ============================================================

    private LocalDate parseDate(String date) {
        if (StringUtils.isBlank(date)) return LocalDate.now();
        try {
            return LocalDate.parse(date);
        } catch (Exception e) {
            log.warn("日期格式非法: {}, 默认当天", date);
            return LocalDate.now();
        }
    }

    private <T> void applyOrderBy(LambdaQueryWrapper<T> wrapper, String orderDir,
                                   com.baomidou.mybatisplus.core.toolkit.support.SFunction<T, ?> column) {
        if ("asc".equalsIgnoreCase(orderDir)) {
            wrapper.orderByAsc(column);
        } else {
            wrapper.orderByDesc(column);
        }
    }

    private void collectFeeders(com.hdkj.fhzg.optimization.response.FeederGroupTreeNode node,
                                 java.util.List<FeederSelectVO> result) {
        if (node.getType() == 4) {
            result.add(new FeederSelectVO(node.getId(), node.getName()));
        }
        if (node.getChildren() != null) {
            for (com.hdkj.fhzg.optimization.response.FeederGroupTreeNode child : node.getChildren()) {
                collectFeeders(child, result);
            }
        }
    }
}