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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hdkj.hussar.ApiResponse;
import com.hdkj.lt.base.constants.DictConstants;
import com.hdkj.lt.base.exception.BusinessException;
import com.hdkj.lt.base.model.response.PageVO;
import com.hdkj.lt.bf.entity.dto.ReconDetailReqDTO;
import com.hdkj.lt.bf.entity.dto.ReconListReqDTO;
import com.hdkj.lt.bf.entity.dto.ReconPageReqDTO;
import com.hdkj.lt.bf.entity.vo.*;
import com.hdkj.lt.bf.mapper.*;
import com.hdkj.lt.bf.service.ReconQueryService;
import com.hdkj.lt.core.bizms.modle.po.FeederTopo;
import com.hdkj.lt.modle.po.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 重构方案查询服务实现
 */
@Service
public class ReconQueryServiceImpl implements ReconQueryService {

    @Autowired
    private FhzgReconResultMapper reconResultMapper;
    @Autowired
    private FhzgReconMetricsMapper reconMetricsMapper;
    @Autowired
    private FhzgReconSwitchSeqMapper reconSwitchSeqMapper;
    @Autowired
    private FhzgReconSwitchOpMapper reconSwitchOpMapper;
    @Autowired
    private FhzgReconFeederResultMapper reconFeederResultMapper;
    @Autowired
    private FhzgReconVolDetailMapper reconVolDetailMapper;
    @Autowired
    private FhzgReconSwitchResultDetailMapper reconSwitchResultDetailMapper;
    @Autowired
    private FeederTopoMapper feederTopoMapper;


    @Override
    public ApiResponse<ReconListVO> getSchemeList(ReconListReqDTO reqDTO) {
        if (Objects.isNull(reqDTO.getEventId())) {
            throw new BusinessException("事件ID为空");
        }

        // 查询事件下所有方案
        List<FhzgReconResult> resultList = reconResultMapper.selectList(
                new LambdaQueryWrapper<FhzgReconResult>()
                        .eq(FhzgReconResult::getEventId, reqDTO.getEventId())
        );
        if(resultList.isEmpty()){
            return ApiResponse.success(new ReconListVO(),"无调优方案");
        }

        // 构建方案VO列表
        List<ReconSchemeVO> schemeList = resultList.stream()
                .map(this::buildSchemeVO)
                .sorted(Comparator.comparing(ReconSchemeVO::getHealthScoreAfter,
                        Comparator.nullsLast(Comparator.reverseOrder())))
                .collect(Collectors.toList());

        // 按健康度排序后第一条为推荐
        if (!schemeList.isEmpty()) {
            schemeList.get(0).setIsRecommend(true);
        }

        // 组装返回
        ReconListVO vo = new ReconListVO();
        ReconListVO.EventInfo eventInfo = new ReconListVO.EventInfo();
        eventInfo.setEventId(reqDTO.getEventId());
        vo.setEventInfo(eventInfo);
        vo.setSchemeList(schemeList);
        return ApiResponse.success(vo);
    }

    @Override
    public ReconDetailVO getSchemeDetail(ReconDetailReqDTO reqDTO) {
        if (Objects.isNull(reqDTO.getId())) {
            throw new BusinessException("方案ID为空");
        }

        FhzgReconResult result = reconResultMapper.selectById(reqDTO.getId());
        if (Objects.isNull(result)) {
            throw new BusinessException("方案不存在");
        }

        // 复用列表的方案构建逻辑
        ReconSchemeVO schemeInfo = buildSchemeVO(result);

        ReconDetailVO vo = new ReconDetailVO();
        vo.setSchemeInfo(schemeInfo);
        return vo;
    }

    @Override
    public List<BreakerAreaVO> getSvgSwitchChange(ReconDetailReqDTO reqDTO) {
        List<FhzgReconSwitchSeq> list = reconSwitchSeqMapper.selectList(
                new LambdaQueryWrapper<FhzgReconSwitchSeq>().eq(FhzgReconSwitchSeq::getResultId, reqDTO.getId()));
        List<BreakerAreaVO> breakerAreaVOS = new ArrayList<>();
        for (FhzgReconSwitchSeq fhzgReconSwitchSeq : list) {
            String startSwitchId = fhzgReconSwitchSeq.getOpenBreakerId();
            String endSwitchId = fhzgReconSwitchSeq.getCloseBreakerId();
            List<FeederTopo> feederTopos = feederTopoMapper.selectList(new LambdaQueryWrapper<FeederTopo>().eq(FeederTopo::getStartKgId, fhzgReconSwitchSeq.getOpenBreakerId()));
            if (CollectionUtils.isEmpty(feederTopos)) {
                FeederTopo feederTopo = feederTopoMapper.selectOne(new LambdaQueryWrapper<FeederTopo>().eq(FeederTopo::getPsrId, fhzgReconSwitchSeq.getOpenBreakerId()));
                startSwitchId = feederTopo.getStartKgId();
            }
            List<String> kgPsrTypes = Arrays.asList(DictConstants.JXZ_KG_PSR_TYPE.split(","));
            List<String> breakerPsrId = feederTopoMapper.getBreakerPsrId(startSwitchId, fhzgReconSwitchSeq.getFeederOutPsrId(), endSwitchId, kgPsrTypes);
            BreakerAreaVO breakerAreaVO = new BreakerAreaVO();
            breakerAreaVO.setStartSwitch(startSwitchId);
            breakerAreaVO.setMidSwitch(breakerPsrId);
            breakerAreaVO.setEndSwitch(Collections.singletonList(endSwitchId));
            breakerAreaVO.setOppositeLineId(fhzgReconSwitchSeq.getFeederInPsrId());
            breakerAreaVOS.add(breakerAreaVO);
        }
        return breakerAreaVOS;
    }

    @Override
    public PageVO<ReconSwitchSeqVO> getSwitchSeqPage(ReconPageReqDTO reqDTO) {
        validatePageParam(reqDTO);

        // 安全校验从主表获取
        FhzgReconResult result = reconResultMapper.selectById(reqDTO.getId());
        Boolean safetyCheckPassed = Objects.nonNull(result) ? result.getFinalCheckIsSafe() : null;
        String safetyCheckReason = Objects.nonNull(result) ? result.getFinalCheckDetails() : null;

        Page<FhzgReconSwitchOp> page = new Page<>(reqDTO.getPageNum(), reqDTO.getPageSize());
        Page<FhzgReconSwitchOp> resultPage = reconSwitchOpMapper.selectPage(page,
                new LambdaQueryWrapper<FhzgReconSwitchOp>()
                        .eq(FhzgReconSwitchOp::getResultId, reqDTO.getId())
                        .orderByAsc(FhzgReconSwitchOp::getOpNo));

        List<FhzgReconSwitchSeq> switchSeqList = reconSwitchSeqMapper.selectList(
                new LambdaQueryWrapper<FhzgReconSwitchSeq>()
                        .eq(FhzgReconSwitchSeq::getResultId, reqDTO.getId()));
        Map<String, Boolean> hotCheckMap = new HashMap<>();
        Map<String, String> hotCheckReasonMap = new HashMap<>();
        switchSeqList.forEach(i -> {
            hotCheckMap.put(i.getOpenBreakerId(), i.getHotCheckIsSafe());
            hotCheckMap.put(i.getCloseBreakerId(), i.getHotCheckIsSafe());
            hotCheckReasonMap.put(i.getOpenBreakerId(), i.getHotCheckReason());
            hotCheckReasonMap.put(i.getCloseBreakerId(), i.getHotCheckReason());

        });

        PageVO<ReconSwitchSeqVO> voPage = new PageVO<>();
        voPage.setTotal(resultPage.getTotal());
        voPage.setPageNum(resultPage.getCurrent());
        voPage.setPageSize(resultPage.getSize());
        List<ReconSwitchSeqVO> collect = resultPage.getRecords().stream().map(this::buildSwitchSeqVO).collect(Collectors.toList());
        collect.forEach(i -> {
            i.setSafetyCheckPassed(safetyCheckPassed);
            i.setSafetyCheckReason(safetyCheckReason);
            i.setHotCheckPassed(hotCheckMap.get(i.getSwitchId()));
            i.setHotCheckReason(hotCheckReasonMap.get(i.getSwitchId()));
        });
        voPage.setRecords(collect);
        return voPage;
    }

    @Override
    public PageVO<ReconFeederCompareVO> getFeederComparePage(ReconPageReqDTO reqDTO) {
        validatePageParam(reqDTO);

        Page<FhzgReconFeederResult> page = new Page<>(reqDTO.getPageNum(), reqDTO.getPageSize());
        Page<FhzgReconFeederResult> resultPage = reconFeederResultMapper.selectPage(page,
                new LambdaQueryWrapper<FhzgReconFeederResult>()
                        .eq(FhzgReconFeederResult::getResultId, reqDTO.getId())
                        .orderByAsc(FhzgReconFeederResult::getFeederNo)
        );

        PageVO<ReconFeederCompareVO> voPage = new PageVO<>();
        voPage.setTotal(resultPage.getTotal());
        voPage.setPageNum(resultPage.getCurrent());
        voPage.setPageSize(resultPage.getSize());
        voPage.setRecords(resultPage.getRecords().stream().map(this::buildFeederCompareVO).collect(Collectors.toList()));
        return voPage;
    }

    @Override
    public PageVO<ReconLoadpointCompareVO> getLoadpointComparePage(ReconPageReqDTO reqDTO) {
        validatePageParam(reqDTO);


        //优先先查越限的，再根据电压变化排序，最多10条
        List<FhzgReconVolDetail> reconVolDetailList = reconVolDetailMapper.getLoadListbySpecRule(reqDTO.getId());
        PageVO<ReconLoadpointCompareVO> voPage = new PageVO<>();
        voPage.setTotal((long) reconVolDetailList.size());
        voPage.setPageNum(Long.valueOf(reqDTO.getPageNum()));
        voPage.setPageSize(Long.valueOf(reqDTO.getPageSize()));
        List<ReconLoadpointCompareVO> collect = reconVolDetailList.stream().map(this::buildLoadpointCompareVO).collect(Collectors.toList());
        int start = (reqDTO.getPageNum() - 1) * reqDTO.getPageSize();
        if (start < 0 || start > reconVolDetailList.size()) {
            voPage.setRecords(new ArrayList<>());
            return voPage;
        }
        int end = Math.min(start + reqDTO.getPageSize(), reconVolDetailList.size());
        voPage.setRecords(collect.subList(start, end));
        return voPage;
    }

    @Override
    public PageVO<ReconSwitchCompareVO> getSwitchComparePage(ReconPageReqDTO reqDTO) {
        validatePageParam(reqDTO);

        Page<FhzgReconSwitchResultDetail> page = new Page<>(reqDTO.getPageNum(), reqDTO.getPageSize());
        Page<FhzgReconSwitchResultDetail> resultPage = reconSwitchResultDetailMapper.selectPage(page,
                new LambdaQueryWrapper<FhzgReconSwitchResultDetail>()
                        .eq(FhzgReconSwitchResultDetail::getResultId, reqDTO.getId())
                        .orderByAsc(FhzgReconSwitchResultDetail::getDetailNo)
        );

        PageVO<ReconSwitchCompareVO> voPage = new PageVO<>();
        voPage.setTotal(resultPage.getTotal());
        voPage.setPageNum(resultPage.getCurrent());
        voPage.setPageSize(resultPage.getSize());
        List<FhzgReconSwitchOp> switchOpsList = reconSwitchOpMapper.selectList(
                new LambdaQueryWrapper<FhzgReconSwitchOp>()
                        .eq(FhzgReconSwitchOp::getResultId, reqDTO.getId())
                        .orderByAsc(FhzgReconSwitchOp::getOpNo));
        Map<String, String> switchMap = new HashMap<>();
        switchOpsList.forEach(i -> {
            switchMap.put(i.getBreakerId(), i.getName());
        });
        List<ReconSwitchCompareVO> collect = resultPage.getRecords().stream().map(this::buildSwitchCompareVO).collect(Collectors.toList());
        collect.forEach(i -> i.setSwitchName(switchMap.get(i.getPsrID())));
        voPage.setRecords(collect);
        return voPage;
    }

    // ==================== 私有方法 ====================

    /**
     * 构建方案VO（列表和详情共用）
     */
    private ReconSchemeVO buildSchemeVO(FhzgReconResult result) {
        ReconSchemeVO vo = new ReconSchemeVO();
        vo.setId(result.getId());
        vo.setSchemeName(result.getSchemeName());
        vo.setEventId(result.getEventId());
        vo.setIsRecommend(false);
        vo.setSafetyCheckPassed(result.getFinalCheckIsSafe());

        // 开关操作次数
        Long switchOpCount = reconSwitchOpMapper.selectCount(
                new LambdaQueryWrapper<FhzgReconSwitchOp>()
                        .eq(FhzgReconSwitchOp::getResultId, result.getId())
        );
        vo.setSwitchOpCount(switchOpCount.intValue());

        // 热校验：所有开关步骤热校验全部通过才为true
        Long hotCheckFailCount = reconSwitchSeqMapper.selectCount(
                new LambdaQueryWrapper<FhzgReconSwitchSeq>()
                        .eq(FhzgReconSwitchSeq::getResultId, result.getId())
                        .eq(FhzgReconSwitchSeq::getHotCheckIsSafe, false)
        );
        vo.setHotCheckPassed(hotCheckFailCount == 0);

        // 查询指标
        FhzgReconMetrics metrics = reconMetricsMapper.selectOne(
                new LambdaQueryWrapper<FhzgReconMetrics>()
                        .eq(FhzgReconMetrics::getResultId, result.getId())
        );
        if (Objects.nonNull(metrics)) {
            vo.setHealthScoreBefore(metrics.getBeforeHealthScore());
            vo.setHealthScoreAfter(metrics.getAfterHealthScore());
            vo.setMaxLoadingPctBefore(metrics.getBeforeLoadingMaxLoadingPct());
            vo.setMaxLoadingPctAfter(metrics.getAfterLoadingMaxLoadingPct());
            vo.setVoltageOverLimitCountBefore(
                    sumInt(metrics.getBeforeVoltageOverVmaxCount(), metrics.getBeforeVoltageUnderVminCount()));
            vo.setVoltageOverLimitCountAfter(
                    sumInt(metrics.getAfterVoltageOverVmaxCount(), metrics.getAfterVoltageUnderVminCount()));
            vo.setTotalLossMwBefore(metrics.getBeforeLossTotalLossMw());
            vo.setTotalLossMwAfter(metrics.getAfterLossTotalLossMw());

            // 负载详细指标
            ReconSchemeVO.DetailLoading detailLoading = new ReconSchemeVO.DetailLoading();
            detailLoading.setAvgLoadingPctBefore(metrics.getBeforeLoadingAvgLoadingPct());
            detailLoading.setAvgLoadingPctAfter(metrics.getAfterLoadingAvgLoadingPct());
            detailLoading.setOverLoadLineCountBefore(metrics.getBeforeLoadingLineOverLimitCount());
            detailLoading.setOverLoadLineCountAfter(metrics.getAfterLoadingLineOverLimitCount());
            vo.setDetailLoading(detailLoading);

            // 电压详细指标
            ReconSchemeVO.DetailVoltage detailVoltage = new ReconSchemeVO.DetailVoltage();
            detailVoltage.setOverMaxCountBefore(metrics.getBeforeVoltageOverVmaxCount());
            detailVoltage.setOverMaxCountAfter(metrics.getAfterVoltageOverVmaxCount());
            detailVoltage.setMaxVoltagePu(metrics.getAfterVoltageMaxVmPu());
            detailVoltage.setUnderMinCountBefore(metrics.getBeforeVoltageUnderVminCount());
            detailVoltage.setUnderMinCountAfter(metrics.getAfterVoltageUnderVminCount());
            detailVoltage.setMinVoltagePu(metrics.getAfterVoltageMinVmPu());
            vo.setDetailVoltage(detailVoltage);

            // 损耗详细指标
            ReconSchemeVO.DetailLoss detailLoss = new ReconSchemeVO.DetailLoss();
            detailLoss.setLineLossMwBefore(metrics.getBeforeLossLineLossMw());
            detailLoss.setLineLossMwAfter(metrics.getAfterLossLineLossMw());
            detailLoss.setTrafoLossMwBefore(metrics.getBeforeLossTrafoLossMw());
            detailLoss.setTrafoLossMwAfter(metrics.getAfterLossTrafoLossMw());
            vo.setDetailLoss(detailLoss);

            // 五维度评分
            ReconSchemeVO.Dimensions dimensions = new ReconSchemeVO.Dimensions();
            dimensions.setSafetyScore(metrics.getAfterHealthComponentSafe());
            dimensions.setVoltageScore(metrics.getAfterHealthComponentVoltage());
            dimensions.setLossScore(metrics.getAfterHealthComponentLoss());
            dimensions.setBalanceScore(metrics.getAfterHealthComponentBalance());
            dimensions.setRiskScore(metrics.getAfterHealthComponentRisk());
            vo.setDimensions(dimensions);
        }
        return vo;
    }

    private ReconSwitchSeqVO buildSwitchSeqVO(FhzgReconSwitchOp seq) {
        ReconSwitchSeqVO vo = new ReconSwitchSeqVO();
        vo.setSeqNo(seq.getOpNo());
        vo.setSwitchId(seq.getBreakerId());
        vo.setSwitchName(seq.getName());
        vo.setOperationType(convertOperationType(seq.getOperationType()));
        vo.setIsThreeRemotely(isThreeRemotely(seq.getAutoType()));
        return vo;
    }

    private ReconFeederCompareVO buildFeederCompareVO(FhzgReconFeederResult feeder) {
        ReconFeederCompareVO vo = new ReconFeederCompareVO();
        vo.setFeederNo(feeder.getFeederNo());
        vo.setFeederName(feeder.getName());
        vo.setFlowType(determineFlowType(feeder));
        vo.setRatedCurrent(feeder.getRateCurrent());
        vo.setCurrentBefore(feeder.getBeforeI());
        vo.setCurrentAfter(feeder.getAfterI());
        vo.setLoadingBefore(calcLoadingPct(feeder.getBeforeI(), feeder.getRateCurrent()));
        vo.setLoadingAfter(calcLoadingPct(feeder.getAfterI(), feeder.getRateCurrent()));
        vo.setLoadingChange(calcLoadingChange(feeder.getBeforeI(), feeder.getAfterI(), feeder.getRateCurrent()));
        vo.setLineLossRateBefore(feeder.getLineLossBefore());
        vo.setLineLossRateAfter(feeder.getLineLossAfter());
        return vo;
    }

    private ReconLoadpointCompareVO buildLoadpointCompareVO(FhzgReconVolDetail detail) {
        ReconLoadpointCompareVO vo = new ReconLoadpointCompareVO();
        vo.setDetailNo(detail.getDetailNo());
        vo.setLoadPointName(detail.getName());
        vo.setLoadType(convertLoadType(detail.getLoadType()));
        vo.setVoltageBefore(detail.getBeforeU());
        vo.setVoltageAfter(detail.getAfterU());
        vo.setLowVoltageBefore(detail.getBeforeUlv());
        vo.setLowVoltageAfter(detail.getAfterUlv());
        vo.setActivePowerBefore(detail.getBeforeP());
        vo.setReactivePowerBefore(detail.getBeforeQ());
        vo.setVoltageChange(detail.getAfterU().subtract(detail.getBeforeU()).abs());
        vo.setIsOverLimitBefore(isOverLimit(detail.getBeforeU()));
        vo.setIsOverLimitAfter(isOverLimit(detail.getAfterU()));
        return vo;
    }

    private ReconSwitchCompareVO buildSwitchCompareVO(FhzgReconSwitchResultDetail detail) {
        ReconSwitchCompareVO vo = new ReconSwitchCompareVO();
        vo.setDetailNo(detail.getDetailNo());
        vo.setPsrID(detail.getPsrId());
        vo.setAutoType(convertAutoType(detail.getAutoType()));
        vo.setStateChange(buildStateChange(detail.getBeforeState(), detail.getAfterState()));
        vo.setCurrentBefore(detail.getBeforeI());
        vo.setCurrentAfter(detail.getAfterI());
        vo.setVoltageBefore(detail.getBeforeU());
        vo.setVoltageAfter(detail.getAfterU());
        return vo;
    }

    private void validatePageParam(ReconPageReqDTO reqDTO) {
        if (Objects.isNull(reqDTO.getId())) {
            throw new BusinessException("方案ID为空");
        }
        if (Objects.isNull(reqDTO.getPageNum())) {
            throw new BusinessException("分页页码为空");
        }
        if (Objects.isNull(reqDTO.getPageSize())) {
            throw new BusinessException("分页长度为空");
        }
    }

    /** close→合, open→分 */
    private String convertOperationType(String operationType) {
        if ("close".equals(operationType)) {
            return "合";
        }
        if ("open".equals(operationType)) {
            return "分";
        }
        return operationType;
    }

    /**
     * close→合, open→分
     */
    private String convertAutoType(String operationType) {
        if ("auto".equals(operationType)) {
            return "自动";
        }
        if ("manual".equals(operationType)) {
            return "手动";
        }
        return operationType;
    }

    /**
     * close→合, open→分
     */
    private String convertLoadType(String LoadType) {
        if ("MV_CUSTOMER".equals(LoadType)) {
            return "专变";
        }
        if ("MV_TRAN".equals(LoadType)) {
            return "公变";
        }
        return LoadType;
    }

    private Integer isOverLimit(BigDecimal vol) {
        if (vol.compareTo(new BigDecimal("9.3")) <= 0) {
            return 1;
        } else if (vol.compareTo(new BigDecimal("10.7")) >= 0) {
            return 2;
        }
        return 0;
    }

    /** 判断是否三遥开关 */
    private Boolean isThreeRemotely(String autoType) {
        return "auto".equals(autoType);
    }

    /** 计算负载率(%) = 电流 / 额定电流 * 100 */
    private BigDecimal calcLoadingPct(BigDecimal current, BigDecimal ratedCurrent) {
        if (Objects.isNull(current) || Objects.isNull(ratedCurrent) || ratedCurrent.compareTo(BigDecimal.ZERO) == 0) {
            return null;
        }
        return current.divide(ratedCurrent, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(100));
    }

    /** 计算负载率变化(%) */
    private BigDecimal calcLoadingChange(BigDecimal beforeI, BigDecimal afterI, BigDecimal ratedCurrent) {
        BigDecimal before = calcLoadingPct(beforeI, ratedCurrent);
        BigDecimal after = calcLoadingPct(afterI, ratedCurrent);
        if (Objects.isNull(before) || Objects.isNull(after)) {
            return null;
        }
        return after.subtract(before);
    }

    /** 判断流向类型 */
    private String determineFlowType(FhzgReconFeederResult feeder) {
        if (Objects.isNull(feeder.getBeforeI()) || Objects.isNull(feeder.getAfterI())) {
            return null;
        }
        if (feeder.getAfterI().compareTo(feeder.getBeforeI()) > 0) {
            return "流入馈线";
        }
        return "流出馈线";
    }

    /** 构建状态变化描述 */
    private String buildStateChange(String beforeState, String afterState) {
        String before = convertState(beforeState);
        String after = convertState(afterState);
        if (before.equals(after)) {
            return "-";
        }
        return before + "→" + after;
    }

    /** open→分, close→合 */
    private String convertState(String state) {
        if ("close".equals(state)) {
            return "合";
        }
        if ("open".equals(state)) {
            return "分";
        }
        return state;
    }

    /** 两个Integer求和（null安全） */
    private Integer sumInt(Integer a, Integer b) {
        int sum = 0;
        if (Objects.nonNull(a)) {
            sum += a;
        }
        if (Objects.nonNull(b)) {
            sum += b;
        }
        return sum;
    }
}
