package com.hdkj.lt.mq.service.fault.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.google.common.collect.Lists;
import com.hdkj.hussar.ResultCode;
import com.hdkj.lt.base.constants.DictConstants;
import com.hdkj.lt.base.constants.ErrorLogConstant;
import com.hdkj.lt.base.constants.RedisKeyConstants;
import com.hdkj.lt.base.constants.RocketMQConstants;
import com.hdkj.lt.base.enums.EventTypeEnum;
import com.hdkj.lt.base.enums.OperationStepEnum;
import com.hdkj.lt.core.bizms.modle.dto.TransformerNameDTO;
import com.hdkj.lt.core.bizms.modle.po.*;
import com.hdkj.lt.core.bizms.modle.po.fault.*;
import com.hdkj.lt.core.bizms.modle.po.plan.FhzgInfoBreakerSvgAfter;
import com.hdkj.lt.core.bizms.modle.request.StateEstimationEquipRequest;

import com.hdkj.lt.core.log.exception.ExceptionErrorLogCast;
import com.hdkj.lt.core.log.model.param.ErrorLogParam;
import com.hdkj.lt.core.mq.client.RocketMQTemplate;
import com.hdkj.lt.core.mq.config.RocketMQProperties;
import com.hdkj.lt.core.mq.model.RocketMQMessageEntity;
import com.hdkj.lt.core.plugins.thread.MultiThreadExecuteService;
import com.hdkj.lt.core.sys.dao.FhzgOrganSuffixMapper;
import com.hdkj.lt.core.sys.service.SwitchProtectionSettingsService;
import com.hdkj.lt.feign.IMeasurementApiClient;
import com.hdkj.lt.feign.IRefreshCacheApiClient;
import com.hdkj.lt.modle.dto.jsty.*;
import com.hdkj.lt.modle.vo.svg.LineFileInfoVO;
import com.hdkj.lt.mq.entity.dto.SwitchTreeNode;
import com.hdkj.lt.mq.entity.po.FaultPowerCutSwitchPO;
import com.hdkj.lt.mq.entity.po.FhzgFaultPowerCut;
import com.hdkj.lt.mq.entity.vo.FaultPowerCutVO;
import com.hdkj.lt.mq.entity.vo.FeederDeviceVO;
import com.hdkj.lt.mq.mapper.fault.*;
import com.hdkj.lt.mq.service.base.ISvgFileInfoService;
import com.hdkj.lt.mq.service.base.MessageRetryLogService;
import com.hdkj.lt.mq.service.base.TransferSchemeSwitchProtectionRecommendService;
import com.hdkj.lt.mq.service.fault.*;
import com.hdkj.lt.mq.service.plan.impl.AnalysisTransferResultServiceImpl;
import com.hdkj.lt.utils.tree.FormatTreeUtils;
import com.hdkj.hussar.ApiResponse;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.model.LoginUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.hdkj.lt.base.constants.CommonConstant.FOUR;

/**
 * FhzgFaultTransferSchemeUsers
 *
 * @Description
 * @Author wcx
 * @Date 2025/5/24 11:03
 * @Version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AnalysisFaultTransferResultServiceImpl implements IAnalysisFaultTransferResultService {

    private final FaultAwaitTransferAreaResultMapper awaitTransferAreaResultMapper;
    private final AnalysisFaultTransferSchemeService analysisFaultTransferSchemeService;
    private final FhzgFaultAnalyzeCalculateDecudeService fhzgFaultAnalyzeCalculateDecudeService;
    private final FhzgFaultAnalyzeCalculateDecudeMapper fhzgFaultAnalyzeCalculateDecudeMapper;
    private final FaultPowerCutMapper faultPowerCutMapper;
    private final RocketMQProperties rocketMQProperties;
    private final RocketMQTemplate rocketMQTemplate;
    private final IMeasurementApiClient IMeasurementApiClient;
    private final FaultPowerCutSwitchMapper faultPowerCutSwitchMapper;
    private final MessageRetryLogService messageRetryLogService;
    private final FhzgOrganSuffixMapper fhzgOrganSuffixMapper;
    private final ISvgFileInfoService svgFileInfoService;
    private final FhzgFaultSwitchInfoListMapper switchInfoListMapper;
    private final TransferSchemeSwitchProtectionRecommendService transferSchemeSwitchProtectionRecommendService;
    private final SwitchProtectionSettingsService switchProtectionSettingsService;
    private final AnalysisTransferResultServiceImpl analysisTransferResultService;
    private final IRefreshCacheApiClient refreshCacheApiClient;
    private final MultiThreadExecuteService multiThreadExecuteService;
    private final IFaultAwaitTransferUsersService awaitTransferUsersService;
    private final FaultFhzgReasoningPlatformServiceImpl faultFhzgReasoningPlatformService;
    private final SpringUtils springUtils;

    /**
     * 获取计算推演平台故障转供结果
     *
     * @param faultId
     * @return
     */
    public FaultPowerCutVO getFaultTransferAreaResultByFaultId(@NotNull Long faultId) {
        return awaitTransferAreaResultMapper.selectFaultAndFaultTime(faultId);
    }

    /**
     * 解析转供方案信息
     */
    public String analysisFaultTransferResult(Long faultId) {
        FaultPowerCutVO faultAwaitTransferAreaResult = this.getFaultTransferAreaResultByFaultId(faultId);
        Assert.isTrue(ObjectUtils.isNotEmpty(faultAwaitTransferAreaResult), "未发现故障停电信息或故障转供推演结果!");

        // 分时段查询设备状估数据入参
        StateEstimationEquipRequest stateEstimationEquip = StateEstimationEquipRequest.builder().psrType("dkx")
                .startTime(String.valueOf(faultAwaitTransferAreaResult.getPeriodStartTime()))
                .endTime(String.valueOf(faultAwaitTransferAreaResult.getPeriodEndTime())).build();
        // 故障馈线信息
        String linkLine = faultAwaitTransferAreaResult.getLineId();
        /*// 保存线路开关段信息（20250630改成动态获取svg 弃用原来逻辑）
        feederTopoMapper.deleteDistLineSwitchSectionByLineId(linkLine);
        List<String> kgPsrType = Arrays.asList(DictConstants.KG_PSR_TYPE.split(",")); // 开关类型集合
        List<String> pbPsrType = Arrays.asList(DictConstants.PB_PSR_TYPE.split(",")); // 配电用户类型集合
        //动态切换表名
        ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(faultId, null));
        feederTopoMapper.saveDistLineSwitchSection(linkLine, kgPsrType, pbPsrType);*/

        // 故障开始、结束时间
        LocalDateTime faultStartTime = faultAwaitTransferAreaResult.getFaultStartTime();
        LocalDateTime faultEndTime = faultAwaitTransferAreaResult.getFaultEndTime();

        Optional.ofNullable(faultAwaitTransferAreaResult.getTransferAreaJson())
                .map(e -> JSON.parseObject(e, ApiResponse.class))
                .filter(e -> ObjectUtils.isNotEmpty(e.getData()))
                .map(e -> JSON.parseObject(JSON.toJSONString(e.getData()), ApiDataDTO.class))
                .ifPresent(data -> {
                    // 待转供用户信息
                    List<FaultAwaitTransferUsers> awaitTransferUsers = Lists.newArrayList();
                    // 对侧线路承载能力
                    List<FaultOppositeLineCarryCapacity> lineCarryCapacities = Lists.newArrayList();
                    // 转供方案路径信息
                    List<FaultTransferSchemePathDetail> schemePathDetails = Lists.newArrayList();
                    // 对侧线路负载率信息
                    List<FaultTransferSchemeOppositeLineLoadFactor> oppositeLineLoadFactors = Lists.newArrayList();
                    // 对侧线路联络开关
                    List<FaultOppositeLineConcatSwitch> concatSwitchList = Lists.newArrayList();
                    // 可靠性校验转供用户信息(失电用户和不可转用户)
                    List<FaultTransferSchemeUsers> transferSchemeUsers = Lists.newArrayList();
                    // 转供方案可转用户
                    List<FaultTransferableSchemeUsers> transferableSchemeUsers = Lists.newArrayList();
                    Snowflake snowflake = IdUtil.getSnowflake(1, 1);
                    //转供前开关信息
                    List<AllSwitchInfoListDTO> allSwitchInfoList = data.getAllSwitchInfoList();
                    // 线路额定电流信息
                    List<FeederCheckRuleDTO> feederCheckRuleList = data.getFeederCheckRuleList();
                    Map<String, FeederCheckRuleDTO> feederCheckRuleDTOMap = feederCheckRuleList.stream()
                            .collect(Collectors.toMap(FeederCheckRuleDTO::getFeederId, a -> a,
                                    (existing, replacement) -> existing));
                    LambdaQueryWrapper<FhzgFaultSwitchInfoList> lambdaQueryWrapper = new LambdaQueryWrapper();
                    lambdaQueryWrapper.eq(FhzgFaultSwitchInfoList::getFaultId, faultId);
                    List<FhzgFaultSwitchInfoList> list = switchInfoListMapper.selectList(lambdaQueryWrapper);
                    if (!list.isEmpty()) {
                        switchInfoListMapper.deleteBatchIds(list.stream().map(FhzgFaultSwitchInfoList::getId)
                                .collect(Collectors.toList()));
                    }
                    switchInfoListMapper.insert(FhzgFaultSwitchInfoList.builder()
                            .allSwitchInfoListJson(JSON.toJSONString(allSwitchInfoList)).feederCheckRuleJson(JSON.toJSONString(feederCheckRuleList))
                            .id(snowflake.nextId()).faultId(faultId).build());
                    // 待转供区域数据
                    List<SupplyAreaDTO> supplyAreaList = data.getSupplyAreaList();
                    // 保存检修区间的结束开关
                    if (!CollectionUtils.sizeIsEmpty(supplyAreaList)) {
                        String jxEndBreaker = supplyAreaList.stream().filter(e ->
                                        ObjectUtils.isNotEmpty(e) && ObjectUtils.isNotEmpty(e.getIsolateBreaker()) && StringUtils.isNotEmpty(e.getIsolateBreaker().getBreakerPSRID()))
                                .map(o -> o.getIsolateBreaker().getBreakerPSRID()).collect(Collectors.joining(","));
                        LambdaUpdateWrapper<FaultPowerCutSwitchPO> wrapper = new LambdaUpdateWrapper<>();
                        wrapper.set(FaultPowerCutSwitchPO::getEndSwitch, jxEndBreaker);
                        wrapper.eq(FaultPowerCutSwitchPO::getFaultId, faultId);
                        faultPowerCutSwitchMapper.update(null, wrapper);
                    }

                    // 保存开关段信息
                    fhzgFaultAnalyzeCalculateDecudeService.analyzeCalculateDecudeData(faultId, supplyAreaList);
                    // 处理待转供用户
                    this.dealFaultAwaitTransferUsers(awaitTransferUsers, supplyAreaList, faultId, linkLine, faultStartTime, faultEndTime);

                    // 转供方案组合
                    List<XferPlanDTO> xferFaultList = data.getXferPlanList();
                    //设置额定电流
                    xferFaultList.forEach(e -> {
                        e.getXferSupplyAreaList().forEach(s -> {
                            FeederCheckRuleDTO feederCheckRuleDTO = feederCheckRuleDTOMap.get(s.getLinkLineInfo().getPsrID());
                            if (feederCheckRuleDTO != null) {
                                s.getLinkLineInfo().setRateCurrent(
                                        feederCheckRuleDTO.getRateCurrent());
                            }
                        });
                    });
                    // 待转供对侧线路承载能力
                    this.dealFaultOppositeLineCarryCapacity(lineCarryCapacities, faultId, xferFaultList, stateEstimationEquip, feederCheckRuleDTOMap);
                    Map<Long, XferPlanDTO> xferFaultMap = MapUtil.newHashMap(); // 转供方案信息
                    AtomicReference<Integer> powerOnSuccess = new AtomicReference<>(0); // 方案是否可转供 0-false 1-true
                    xferFaultList.forEach(e -> {
                        Long schemeId = snowflake.nextId(); // 转供方案ID
                        xferFaultMap.put(schemeId, e); // 转供方案组合信息
                        //处理转供方案路径明细信息表
                        this.dealFaultTransferSchemePathDetail(schemePathDetails, e.getXferSupplyAreaList(), schemeId, linkLine, awaitTransferUsers);
                        //处理对侧线路负载率信息
                        this.dealFaultSchemeOppositeLineLoadFactor(oppositeLineLoadFactors, concatSwitchList, e.getXferSupplyAreaList(), schemeId, powerOnSuccess, feederCheckRuleDTOMap);
                        // 处理可靠性校验转供用户和可转供用户
                        this.dealFaultTransferSchemeUsers(transferSchemeUsers, transferableSchemeUsers, e.getXferSupplyAreaList(), schemeId, faultStartTime, faultEndTime);
                        // 处理保护定值推荐
                        this.dealProtectionRecommend(e.getXferSupplyAreaList(), schemeId);
                    });
                    // 更新故障停电方案是否可转供字段
                    faultPowerCutMapper.updateById(FhzgFaultPowerCut.builder().powerOnSuccess(powerOnSuccess.get()).id(faultId).build());
                    // 转供方案组合入库
                    analysisFaultTransferSchemeService.analysisFaultTransferScheme(faultId, xferFaultMap, awaitTransferUsers);
                    // 待转供用户信息
                    Optional.ofNullable(awaitTransferUsers).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IFaultAwaitTransferUsersService.class));
                    // 对侧线路承载能力
                    Optional.ofNullable(lineCarryCapacities).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IFaultOppositeLineCarryCapacityService.class));
                    // 转供方案路径信息
                    Optional.ofNullable(schemePathDetails).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IFaultTransferSchemePathDetailService.class));
                    // 对侧线路负载率信息
                    Optional.ofNullable(oppositeLineLoadFactors).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IFaultSchemeOppositeLineLoadFactorService.class));
                    // 可靠性校验转供用户信息
                    Optional.ofNullable(transferSchemeUsers).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IFaultTransferSchemeUsersService.class));
                    // 可转供用户信息
                    Optional.ofNullable(transferableSchemeUsers).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IFaultTransferableSchemeUsersService.class));

                    //对侧线路联络开关
                    if (concatSwitchList != null && concatSwitchList.size() > 0) {
                        fhzgFaultAnalyzeCalculateDecudeMapper.saveConcatSwitchList(concatSwitchList);
                    }
                    /*// 删除 开始开关在 concatSwitchList 中的数据（20250617-修改开关段入库逻辑后，此删除动作弃用）
                    fhzgFaultAnalyzeCalculateDecudeMapper.deleteSwitchSectionByConnect(faultId);*/
                    // 更新开关段负荷
                    fhzgFaultAnalyzeCalculateDecudeMapper.updateSwitchSectionSwitchLoads(faultId);
                    //  统计转供后 有功、无功、电流
                    this.dealFhzgInfoBreakerSvgAfter(linkLine, faultId);
                    // 开关动作和合环校验信息
                    fhzgFaultAnalyzeCalculateDecudeService.analyzeXferFaultList(faultId, xferFaultMap, data.getLoopCheckRule(), feederCheckRuleDTOMap);
                    // 更新开关动作是否 联络开关
                    fhzgFaultAnalyzeCalculateDecudeMapper.updateSwitchingSequenceIsConnect(faultId);
                    // 停电区域列表
//                    List<PowerOutageAreaDTO> powerOutageAreaList = data.getPowerOutageAreaList();

                    // 获取并设置方案对应的文件信息
                    xferFaultMap.forEach((key, val) -> {
                        LineFileInfoVO svgGenerationFile = svgFileInfoService.getSvgGenerationFile(linkLine, key, FOUR);
                        if (svgGenerationFile == null) {
                            ErrorLogParam errorLogParam = new ErrorLogParam()
                                    .setErrorTime(LocalDateTime.now())
                                    .setEventType(EventTypeEnum.TOPO_FILE.getCode())
                                    .setEventId(faultId.toString())
                                    .setStage(ErrorLogConstant.Stage.GET_SVG_TOPO)
                                    .setErrorLevel("Warning")
                                    .setSourceSystem(ErrorLogConstant.SourceSystem.FHZG)
                                    .setOperationStep(OperationStepEnum.FAULT.getName())
                                    .setRelatedId(key.toString())
                                    .setErrorCategory("方案成图失败")
                                    .setRelatedCategory("fhzg_fault_transfer_scheme")
                                    .setDetails("故障id：" + faultId + "方案id：" + key + " 成图服务报错，请求参数: lineId:" + linkLine + ", objId" + key + ", type:" + FOUR);
                            ExceptionErrorLogCast.cast(errorLogParam);
                        }
                    });
                });
        faultFhzgReasoningPlatformService.saveFaultFile(linkLine, faultId);
        // MQ消息发送
        this.sendRocketMQMessage(faultId);
        // 生成动画反演数据
        CompletableFuture.runAsync(() -> refreshCacheApiClient.generateCartoonData(faultId, "2"), multiThreadExecuteService.getExecutor());
        return ResultCode.SUCCESS.getMessage();
    }

    /**
     * 处理待转供用户
     */
    private void dealFaultAwaitTransferUsers(List<FaultAwaitTransferUsers> dataList, List<SupplyAreaDTO> supplyAreaList,
                                             Long faultId, String linkLine, LocalDateTime faultStartTime, LocalDateTime faultEndTime) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 待转供用户数据
        List<String> trans = Lists.newArrayList();
        List<String> customers = Lists.newArrayList();
        Map<String, TransformerNameDTO> transfermerNameMap = awaitTransferUsersService.getTransformerName();

        supplyAreaList.forEach(e -> {
            Optional.ofNullable(e.getAreaDevice()).ifPresent(en -> {
                if (ObjectUtils.isNotEmpty(en.getMvTransList())) {
                    en.getMvTransList().forEach(device -> {
                        trans.add(device.getPsrID());
                        FaultAwaitTransferUsers awaitTransferUser = new FaultAwaitTransferUsers();
                        awaitTransferUser.setTransformerNo(device.getPsrID())
                                .setTransformerName(getTransformerNameByTransformerNo(device.getPsrID(), device.getName(), transfermerNameMap))
                                .setDeviceType(device.getPsrType())
                                .setUserLoads(this.getMetricValue(device.getP()))
                                .setUserCurrent(this.getMetricValue(device.getI()))
                                .setUserVoltage(this.getMetricValue(device.getU()))
                                .setUserReactivePower(this.getMetricValue(device.getQ()))
                                .setFaultId(faultId).setCreateTime(LocalDateTime.now());
                        Optional.ofNullable(loginUser).ifPresent(user -> awaitTransferUser.setCreator(loginUser.getUserid()));
                        dataList.add(awaitTransferUser);
                    });
                }
                if (ObjectUtils.isNotEmpty(en.getMvCustomerList())) {
                    en.getMvCustomerList().forEach(device -> {
                        customers.add(device.getPsrID());
                        FaultAwaitTransferUsers awaitTransferUser = new FaultAwaitTransferUsers();
                        awaitTransferUser.setTransformerNo(device.getPsrID())
                                .setTransformerName(getTransformerNameByTransformerNo(device.getPsrID(), device.getName(), transfermerNameMap))
                                .setUserLoads(this.getMetricValue(device.getP()))
                                .setUserCurrent(this.getMetricValue(device.getI()))
                                .setUserVoltage(this.getMetricValue(device.getU()))
                                .setUserReactivePower(this.getMetricValue(device.getQ()))
                                .setFaultId(faultId).setCreateTime(LocalDateTime.now());
                        Optional.ofNullable(loginUser).ifPresent(user -> awaitTransferUser.setCreator(loginUser.getUserid()));
                        dataList.add(awaitTransferUser);
                    });
                }
            });
        });
        if (ObjectUtils.isNotEmpty(ListUtils.union(trans, customers))) {
            //动态切换表名
            //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(faultId, null));
            // 根据psrId查询开关段
            List<FaultAwaitTransferSwitchSection> switchSectionL = fhzgFaultAnalyzeCalculateDecudeMapper.getSwitchSectionList(linkLine,
                    ListUtils.union(trans, customers), Arrays.asList(DictConstants.PB_PSR_TYPE.split(",")), faultId);
            Map<String, FaultAwaitTransferSwitchSection> switchSectionMap = switchSectionL.stream().collect(Collectors.toMap(k -> k.getPsrId(), v -> v));

            // 获取变压器用户的信息
            List<FhzgDistTransformerCustomer> transformerCustomer = awaitTransferAreaResultMapper.getTransformerCustomerInfo(trans, customers, faultStartTime, faultEndTime);
            Map<String, FhzgDistTransformerCustomer> customer = transformerCustomer.stream().collect(Collectors.toMap(FhzgDistTransformerCustomer::getTransformerNo, entity -> entity));
            dataList.forEach(e -> {
                FaultAwaitTransferSwitchSection awaitTransferSwitchSection = switchSectionMap.get(e.getTransformerNo());
                // 设置重要用户、敏感用户、保电用户、所属开关段信息
                FhzgDistTransformerCustomer transUser = customer.get(e.getTransformerNo());
                e.setSwitchSectionName(Optional.ofNullable(awaitTransferSwitchSection).map(en -> en.getStartSwitchName()).orElse(null))
                        .setSwitchSectionId(Optional.ofNullable(awaitTransferSwitchSection).map(i -> i.getId() == null ? null : i.getId().toString()).orElse(null))
                        .setIsCriticalUser(Optional.ofNullable(transUser).map(en -> en.getIsCriticalUser()).orElse("0"))
                        .setIsSensitiveUser(Optional.ofNullable(transUser).map(en -> en.getIsSensitiveUser()).orElse("0"))
                        .setIsDualPower(Optional.ofNullable(transUser).map(en -> en.getIsDualPower()).orElse("0"))
                        .setIsProtectPower(Optional.ofNullable(transUser).map(en -> en.getIsProtectPower()).orElse("0"));
            });
        }
    }

    //中压用户接入点名称改造
    private String getTransformerNameByTransformerNo(String transformerNo, String transformerName, Map<String, TransformerNameDTO> transfermerNameMap) {
        TransformerNameDTO transformerNameDTO = transfermerNameMap.get(transformerNo);
        if (transformerNameDTO == null || transformerNameDTO.getTransformerName() == null) {
            if (transformerNameDTO == null || transformerNameDTO.getDedicatedName() == null) {
                return transformerName;
            } else {
                return transformerNameDTO.getDedicatedName();
            }
        }
        return transformerNameDTO.getTransformerName();
    }

    /**
     * 对侧线路承载能力
     */
    private void dealFaultOppositeLineCarryCapacity(List<FaultOppositeLineCarryCapacity> dataList, Long faultId,
                                                    List<XferPlanDTO> supplyAreaList, StateEstimationEquipRequest stateEstimationEquip,
                                                    Map<String, FeederCheckRuleDTO> feederCheckRuleDTOMap) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        List<FaultOppositeLineCarryCapacity> tempDataList = Lists.newArrayList();
        // 对侧线路承载能力数据
        supplyAreaList.forEach(e -> {
            LocalDateTime nowDateTime = LocalDateTime.now();
            // 转供方案的的对侧线路信息
            Optional.ofNullable(e.getXferSupplyAreaList())
                    .filter(ObjectUtils::isNotEmpty)
                    .ifPresent(en -> en.forEach(fault -> {
                        FaultOppositeLineCarryCapacity lineCarryCapacity = new FaultOppositeLineCarryCapacity();
                        Optional.ofNullable(fault.getLinkLineInfo()).ifPresent(line -> {
                            FeederCheckRuleDTO feederCheckRuleDTO = feederCheckRuleDTOMap.get(line.getPsrID());
                            lineCarryCapacity.setLineId(Optional.ofNullable(line.getPsrID()).orElse(null))
                                    .setLineName(Optional.ofNullable(line.getName()).orElse(null))
                                    .setFaultId(faultId).setCreateTime(nowDateTime);
                            if (feederCheckRuleDTO != null) {
                                lineCarryCapacity.setRatedCurrent(BigDecimal.valueOf(feederCheckRuleDTO.getRateCurrent()));
                            }
                            Optional.ofNullable(loginUser).ifPresent(user -> lineCarryCapacity.setCreator(loginUser.getUserid()));
                            tempDataList.add(lineCarryCapacity);
                        });
                    }));
        });
        // 对侧线路承载能力的去重
        dataList.addAll(tempDataList.stream().filter(distinctByKey(FaultOppositeLineCarryCapacity::getLineId)).collect(Collectors.toList()));

        // 获取最大电流信息负载计算等信息
        stateEstimationEquip.setPsrIds(dataList.stream().map(e -> e.getLineId()).collect(Collectors.toList()));
        // 调用实时量测接口获取七天最大电流值，判断接口返回情况，错误时防止解析中断
        ApiResponse<Map<String, BigDecimal>> lineIResp = new ApiResponse<>();
        try {
            lineIResp = IMeasurementApiClient.queryPeriodByCommonQuery(stateEstimationEquip);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("故障方案解析---获取七天最大电流值 参数:{}, 结果:{}", stateEstimationEquip, lineIResp);
        if (lineIResp.getCode() == ResultCode.SUCCESS.getCode() && ObjectUtils.isNotEmpty(lineIResp.getData())) {
            Map<String, BigDecimal> lineIMap = lineIResp.getData(); // 线路的七天最大电流值Map
            // 获取线路计算需要的电压依赖数据
            List<String> LineIds = dataList.stream().map(FaultOppositeLineCarryCapacity::getLineId).collect(Collectors.toList());
            List<FeederDeviceVO> feederDeviceList = fhzgFaultAnalyzeCalculateDecudeMapper.getLineVoltageByLineId(LineIds);
            Map<String, FeederDeviceVO> lineVoltMap = feederDeviceList.stream().collect(Collectors.toMap(e -> e.getPsrId(), e -> e));
            dataList.forEach(e -> {
                // 7天最大电流 单位是A无需转换和状估接口不一样
                BigDecimal maxCurrent = Optional.ofNullable(lineIMap.get(e.getLineId())).orElse(null);
                // 额定电流(最大允许电流)
                BigDecimal ratedCurrent = e.getRatedCurrent();
                if (ObjectUtils.allNotNull(maxCurrent, ratedCurrent)) {
                    // 最大负载率
                    BigDecimal maxLoadFactor;
                    if (ratedCurrent.compareTo(BigDecimal.ZERO) != 0) {
                        maxLoadFactor = maxCurrent.divide(ratedCurrent, 4, RoundingMode.HALF_UP);
                    } else {
                        maxLoadFactor = BigDecimal.ZERO;
                    }
                    if (ObjectUtils.isNotEmpty(lineVoltMap.get(e.getLineId()))) {
                        // 电压等级的计算值
                        BigDecimal voltValue = new BigDecimal(lineVoltMap.get(e.getLineId()).getVoltValue());
                        if (ObjectUtils.isNotEmpty(voltValue)) {
                            // 可带供容量的数据计算
                            BigDecimal bigDecimal = ratedCurrent.multiply(voltValue).multiply(BigDecimal.valueOf(Math.sqrt(3)));
                            BigDecimal deliverableCapacity = bigDecimal.subtract(bigDecimal.multiply(maxLoadFactor));
                            // 20250618添加逻辑 当可带供容量为负数时设置为0
                            deliverableCapacity = deliverableCapacity.compareTo(BigDecimal.ZERO) == -1 ? BigDecimal.ZERO : deliverableCapacity;
                            e.setMaxLoadFactor(maxLoadFactor.multiply(BigDecimal.valueOf(100.0))).setMaxCurrent(maxCurrent).setDeliverableCapacity(deliverableCapacity)
                                    .setRatedCapacity(Optional.ofNullable(lineVoltMap.get(e.getLineId()).getFeederRateCapacity()).map(BigDecimal::new).orElse(null));
                        }
                    }
                }
            });
        }
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    /**
     * 处理转供路径明细
     */
    private void dealFaultTransferSchemePathDetail(List<FaultTransferSchemePathDetail> dataList, List<XferSupplyAreaDTO> supplyAreaList,
                                                   Long schemeId, String lineId, List<FaultAwaitTransferUsers> awaitTransferUsers) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        supplyAreaList.forEach(e -> {
            String startSwitchId = Optional.ofNullable(e.getIsolateBreaker()).map(en -> en.getBreakerPSRID()).orElse(null);
            String startSwitchName = Optional.ofNullable(e.getIsolateBreaker()).map(en -> en.getBreakerName()).orElse(null);
            // 对线线路存在时映射对应的值
            FaultTransferSchemePathDetail schemePathDetail = new FaultTransferSchemePathDetail();
            // 对侧线路
            Optional.ofNullable(e.getLinkLineInfo()).ifPresent(linkLine -> {
                schemePathDetail.setOppositeLineId(Optional.ofNullable(linkLine.getPsrID()).orElse(null))
                        .setOppositeLineName(Optional.ofNullable(linkLine.getName()).orElse(null))
                        .setLoadFactor(Optional.ofNullable(linkLine.getPlanMaxCurrentLoad()).map(BigDecimal::valueOf).orElse(null))
                        .setSchemeId(schemeId).setCreateTime(LocalDateTime.now());
                Optional.ofNullable(loginUser).ifPresent(user -> schemePathDetail.setCreator(loginUser.getUserid()));
            });
            // 联络开关信息
            String linkSwitchId = Optional.ofNullable(e.getLinkSwitch()).map(LinkSwitchDTO::getPsrID).orElse("-");
            // 临界开关信息
            Optional.ofNullable(e.getLinkSwitch()).ifPresent(linkSwitch -> {
                schemePathDetail.setSwitchId(Optional.ofNullable(linkSwitch.getPsrID()).orElse(null))
                        .setSwitchName(Optional.ofNullable(linkSwitch.getName()).orElse(null));
            });
            // 开关段信息
            Optional.ofNullable(e.getSwitchInfoList()).ifPresent(switchList -> {
                // 设置起点开关
                schemePathDetail.setStartSwitchId(startSwitchId).setStartSwitchName(startSwitchName);
                // 终点开关ID集合（可能不包含未启用的联络开关）
                List<String> endSwitchIds = switchList.stream()
                        .filter(en -> !StringUtils.equalsAny(en.getSwitchId(), startSwitchId, linkSwitchId))
                        .map(SwitchInfoDTO::getSwitchId).collect(Collectors.toList());
                List<String> switchTypes = Arrays.asList(DictConstants.KG_PSR_TYPE.split(","));
                //动态切换表名
                //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(null, lineId));
                // 查询中间和结束开关，并设置中间、结束开关信息
                List<SwitchInfoDTO> switchSectionList = awaitTransferAreaResultMapper.getSwitchSectionInfo(lineId, startSwitchId, linkSwitchId, endSwitchIds, switchTypes);
                if (ObjectUtils.isNotEmpty(switchSectionList)) {
                    // 处理中间开关和结束开关
                    Map<String, SwitchInfoDTO> switchInfoMap = switchSectionList.stream()
                            .collect(Collectors.groupingBy(
                                    SwitchInfoDTO::getSwitchType,
                                    Collectors.collectingAndThen(
                                            Collectors.reducing((s1, s2) -> SwitchInfoDTO.builder()
                                                    .switchId(String.format("%s,%s", s1.getSwitchId(), s2.getSwitchId()))
                                                    .switchName(String.format("%s,%s", s1.getSwitchName(), s2.getSwitchName())).build()),
                                            Optional::get)
                            ));
                    // 中间开关信息
                    SwitchInfoDTO midSwitchInfo = Optional.ofNullable(switchInfoMap.get("mid")).orElse(SwitchInfoDTO.builder().build());
                    // 结束开关信息
                    SwitchInfoDTO endSwitchInfo = Optional.ofNullable(switchInfoMap.get("end")).orElse(SwitchInfoDTO.builder().build());
                    schemePathDetail.setSwitchSectionId(midSwitchInfo.getSwitchId()).setSwitchSectionName(midSwitchInfo.getSwitchName())
                            .setEndSwitchId(endSwitchInfo.getSwitchId()).setEndSwitchName(endSwitchInfo.getSwitchName());
                }
            });
            // 取出本区域的所有的转供用户
            List<String> userList = Lists.newArrayList();
            Optional.ofNullable(e.getAreaDeviceInfo()).ifPresent(device -> {
                userList.addAll(device.getMvTransList().stream().map(TransCustomerDTO::getPsrID).collect(Collectors.toList()));
                userList.addAll(device.getMvCustomerList().stream().map(TransCustomerDTO::getPsrID).collect(Collectors.toList()));
            });
            // 在待转供用户找到负荷开关负载累加，设置开关段负荷
            double userSum = awaitTransferUsers.stream()
                    .filter(en -> userList.contains(en.getTransformerNo()) && ObjectUtils.isNotEmpty(en.getUserLoads()))
                    .map(en -> en.getUserLoads()).mapToDouble(BigDecimal::doubleValue).sum();
            BigDecimal sum = BigDecimal.valueOf(userSum).setScale(6, RoundingMode.HALF_UP);
            schemePathDetail.setSwitchSectionLoads(sum);
            // 开关段信息
            dataList.add(schemePathDetail);
        });
    }

    /**
     * 处理对侧线路负载率信息
     */
    private void dealFaultSchemeOppositeLineLoadFactor(List<FaultTransferSchemeOppositeLineLoadFactor> dataList, List<FaultOppositeLineConcatSwitch> switchList,
                                                       List<XferSupplyAreaDTO> supplyAreaList, Long schemeId, AtomicReference<Integer> powerOnSuccess, Map<String, FeederCheckRuleDTO> feederCheckRuleDTOMap) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        supplyAreaList.forEach(e -> {
            if (Integer.compare(powerOnSuccess.get(), 0) == 0) {
                powerOnSuccess.set(Objects.equals(e.getPowerOnSuccess(), Boolean.TRUE) ? 1 : 0);
            }
            // 可转区域的公变的电流和
            Double transISum = Optional.ofNullable(e.getAreaDeviceInfo())
                    .filter(en -> Objects.equals(e.getPowerOnSuccess(), Boolean.TRUE) && ObjectUtils.isNotEmpty(en.getMvTransList()))
                    .map(en -> en.getMvTransList().stream().filter(val -> val.getI() != null && val.getI().getValue() != null).mapToDouble(val -> val.getI().getValue()).sum())
                    .orElse(0.0);
            // 可转区域的中压用户的电流和
            Double customerISum = Optional.ofNullable(e.getAreaDeviceInfo())
                    .filter(en -> Objects.equals(e.getPowerOnSuccess(), Boolean.TRUE) && ObjectUtils.isNotEmpty(en.getMvCustomerList()))
                    .map(en -> en.getMvCustomerList().stream().filter(val -> val.getI() != null && val.getI().getValue() != null).mapToDouble(val -> val.getI().getValue()).sum())
                    .orElse(0.0);
            // 对线线路存在时映射对应的值
            Optional.ofNullable(e.getLinkLineInfo()).ifPresent(linkLine -> {
                Snowflake snowflake = IdUtil.getSnowflake(1, 1);
                Long lineLoadFactorId = snowflake.nextId(); //对侧线路负载率ID
                FaultTransferSchemeOppositeLineLoadFactor oppositeLineLoadFactor = new FaultTransferSchemeOppositeLineLoadFactor();
                // 计算转供前对侧线路负载率
                BigDecimal beforeLoadFactor = Optional.ofNullable(linkLine.getPlanMaxCurrentValue())
                        .filter(en -> ObjectUtils.isNotEmpty(linkLine.getRateCurrent()) && linkLine.getRateCurrent() != 0)
                        .map(en -> BigDecimal.valueOf(en)
                                .subtract(BigDecimal.valueOf(transISum + customerISum))
                                .multiply(BigDecimal.valueOf(100.0))
                                .divide(BigDecimal.valueOf(linkLine.getRateCurrent()), 2, RoundingMode.HALF_UP))
                        .orElse(null);
                FeederCheckRuleDTO feederCheckRuleDTO = feederCheckRuleDTOMap.get(linkLine.getPsrID());
                oppositeLineLoadFactor.setOppositeLineId(Optional.ofNullable(linkLine.getPsrID()).orElse(null))
                        .setOppositeLineName(Optional.ofNullable(linkLine.getName()).orElse(null))
                        .setLoadFactor(Optional.ofNullable(linkLine.getPlanMaxCurrentLoad()).map(BigDecimal::valueOf).orElse(null))
                        .setCalculatedCurrent(Optional.ofNullable(linkLine.getPlanMaxCurrentValue()).map(BigDecimal::valueOf).orElse(null))
                        .setBeforeLoadFactor(beforeLoadFactor).setSchemeId(schemeId).setCreateTime(LocalDateTime.now()).setId(lineLoadFactorId);
                if (feederCheckRuleDTO != null) {
                    oppositeLineLoadFactor.setRatedCurrent(BigDecimal.valueOf(feederCheckRuleDTO.getRateCurrent()));
                }
                Optional.ofNullable(loginUser).ifPresent(user -> oppositeLineLoadFactor.setCreator(loginUser.getUserid()));
                dataList.add(oppositeLineLoadFactor);

                Optional.ofNullable(e.getLinkSwitch()).ifPresent(linkSwitch -> {
                    FaultOppositeLineConcatSwitch lineConcatSwitch = new FaultOppositeLineConcatSwitch();
                    lineConcatSwitch.setSchemeId(schemeId).setCapacityId(lineLoadFactorId)
                            .setConcatPsrId((Optional.ofNullable(linkSwitch.getPsrID()).orElse(null)))
                            .setConcatPsrName((Optional.ofNullable(linkSwitch.getName()).orElse(null)));
                    switchList.add(lineConcatSwitch);
                });
            });
        });
    }

    /**
     * 处理可靠性校验转供用户
     */
    private void dealFaultTransferSchemeUsers(List<FaultTransferSchemeUsers> dataList, List<FaultTransferableSchemeUsers> transferableUsers,
                                              List<XferSupplyAreaDTO> supplyAreaList, Long schemeId, LocalDateTime faultStartTime, LocalDateTime faultEndTime) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 可靠性校验转供用户数据
        List<String> trans = Lists.newArrayList();
        List<String> customers = Lists.newArrayList();
        List<FaultTransferSchemeUsers> tempDataList = Lists.newArrayList();
        supplyAreaList.forEach(e -> {
            // 用户起点开关ID、名称信息
            String startSwitchId = Optional.ofNullable(e.getIsolateBreaker()).map(BreakerInfoDTO::getBreakerPSRID).orElse(null);
            String startSwitchName = Optional.ofNullable(e.getIsolateBreaker()).map(BreakerInfoDTO::getBreakerName).orElse(null);
            // 默认数据类型为hot热倒
            AtomicReference<String> dataType = new AtomicReference<>("3");
            if (!Objects.equals(e.getPowerOnSuccess(), Boolean.TRUE)) {
                dataType.set("1"); // 只有不存在专供方案时
            } else if (StringUtils.equals(e.getXferType(), "cold")) {
                dataType.set("2"); // 冷倒时
            }
            Optional.ofNullable(e.getAreaDeviceInfo()).ifPresent(en -> {
                if (ObjectUtils.isNotEmpty(en.getMvTransList())) {
                    // 转供公变用户
                    en.getMvTransList().forEach(device -> {
                        trans.add(device.getPsrID());
                        FaultTransferSchemeUsers transferSchemeUser = new FaultTransferSchemeUsers();
                        transferSchemeUser.setTransformerNo(device.getPsrID())
                                .setTransformerName(device.getName())
                                .setCustType("公变").setDataType(dataType.get())
                                .setStartSwitchId(startSwitchId).setStartSwitchName(startSwitchName)
                                .setActivePower(this.getMetricValue(device.getP()))
                                .setUserCurrent(this.getMetricValue(device.getI()))
                                .setUserVoltage(this.getMetricValue(device.getU()))
                                .setUserReactivePower(this.getMetricValue(device.getQ()))
                                .setSchemeId(schemeId).setCreateTime(LocalDateTime.now());
                        Optional.ofNullable(loginUser).ifPresent(user -> transferSchemeUser.setCreator(loginUser.getUserid()));
                        tempDataList.add(transferSchemeUser);
                    });
                }
                if (ObjectUtils.isNotEmpty(en.getMvCustomerList())) {
                    // 转供中压用户
                    en.getMvCustomerList().forEach(device -> {
                        customers.add(device.getPsrID());
                        FaultTransferSchemeUsers transferSchemeUser = new FaultTransferSchemeUsers();
                        transferSchemeUser.setTransformerNo(device.getPsrID())
                                .setTransformerName(device.getName())
                                .setCustType("中压用户").setDataType(dataType.get())
                                .setStartSwitchId(startSwitchId).setStartSwitchName(startSwitchName)
                                .setActivePower(this.getMetricValue(device.getP()))
                                .setUserCurrent(this.getMetricValue(device.getI()))
                                .setUserVoltage(this.getMetricValue(device.getU()))
                                .setUserReactivePower(this.getMetricValue(device.getQ()))
                                .setSchemeId(schemeId).setCreateTime(LocalDateTime.now());
                        Optional.ofNullable(loginUser).ifPresent(user -> transferSchemeUser.setCreator(loginUser.getUserid()));
                        tempDataList.add(transferSchemeUser);
                    });
                }
            });
        });

        Map<String, FhzgDistTransformerCustomer> customer = MapUtil.newHashMap();
        if (ObjectUtils.isNotEmpty(ListUtils.union(trans, customers))) {
            // 获取变压器用户的信息
            List<FhzgDistTransformerCustomer> transformerCustomer = awaitTransferAreaResultMapper.getTransformerCustomerInfo(trans, customers, faultStartTime, faultEndTime);
            customer.putAll(transformerCustomer.stream().collect(Collectors.toMap(FhzgDistTransformerCustomer::getTransformerNo, entity -> entity)));
        }
        tempDataList.forEach(e -> {
            FhzgDistTransformerCustomer transUser = customer.get(e.getTransformerNo());
            // 重要用户标记
            String criticalUser = Optional.ofNullable(transUser).map(en -> en.getIsCriticalUser()).orElse("0");
            // 敏感用户标记
            String sensitiveUser = Optional.ofNullable(transUser).map(en -> en.getIsSensitiveUser()).orElse("0");
            // 保电用户标记
            String protectPower = Optional.ofNullable(transUser).map(en -> en.getIsProtectPower()).orElse("0");
            // 设置重要用户、敏感用户、保电用户
            e.setIsCriticalUser(criticalUser).setIsSensitiveUser(sensitiveUser)
                    .setIsProtectPower(protectPower);
            /** 用户分为两类：
             *  1- 失电用户（包含不可转+可转但是冷倒的用户）
             *  2- 可转用户（冷倒+热倒的用户）
             */
            if (StringUtils.equals(e.getDataType(), "1")) {
                dataList.add(e); // 添加不可转用户
            } else {
                // 可转供但是冷倒的用户，只需要敏感或者重要用户或保电用户算失电
                if (StringUtils.equals(e.getDataType(), "2") && StringUtils.equalsAny("1", criticalUser, sensitiveUser, protectPower)) {
                    dataList.add(e); // 添加冷倒转的敏感或者重要失电用户
                }
                FaultTransferableSchemeUsers transferableUser = BeanUtil.copyProperties(e, FaultTransferableSchemeUsers.class);
                // 公变且电压等级有值时，计算是否低电压配电
                if (StringUtils.equals("公变", transferableUser.getCustType()) && ObjectUtils.isNotEmpty(transferableUser.getUserVoltage())) {
                    // 有值直接转换成V
                    BigDecimal bigDecimal = transferableUser.getUserVoltage().multiply(BigDecimal.valueOf(1000L));
                    if (BigDecimal.valueOf(204.6).compareTo(bigDecimal) == 1) {
                        transferableUser.setIsLvTransformer("1"); // 比204.6小直接低电压
                    } else {
                        BigDecimal calculate = BigDecimal.valueOf(220L);
                        BigDecimal volValue = bigDecimal.subtract(calculate).divide(calculate, 2, RoundingMode.HALF_UP);
                        transferableUser.setIsLvTransformer(BigDecimal.valueOf(-0.07).compareTo(volValue) == 1 ? "1" : "0");
                    }
                }
                transferableUsers.add(transferableUser);
            }
        });
    }

    /**
     * 根据指定service类动态保存数据
     */
    private <T> void dynamicBatchSave(List<T> dataList, Class<? extends IService<T>> serviceClazz) {
        IService<T> service = SpringUtils.getBean(serviceClazz);
        service.saveBatch(dataList);
    }

    /**
     * 处理转供后 有功、无功、电流
     */
    private void dealFhzgInfoBreakerSvgAfter(String lineId, Long faultId) {
        // 开关段类型
        List<String> switchList = Arrays.asList(DictConstants.KG_PSR_TYPE.split(","));
        // 配电类型
        List<String> transformerList = Arrays.asList(DictConstants.PB_PSR_TYPE.split(","));
        //动态切换表名
        //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(null, lineId));
        // 获取方案和开关用户信息
        List<SwitchTreeNode> treeNodes = awaitTransferAreaResultMapper.getBreakerSvgAfter(lineId, faultId, ListUtils.union(switchList, transformerList));
        if (ObjectUtils.isNotEmpty(treeNodes)) {
            // 递归计算IPQ值的累加
            Map<Long, List<SwitchTreeNode>> treeMap = treeNodes.stream().collect(Collectors.groupingBy(SwitchTreeNode::getSchemeId));
            List<FhzgInfoBreakerSvgAfter> breakerSvgAfters = Lists.newArrayList();
            treeMap.forEach((key, values) -> {
                List<SwitchTreeNode> treeNodeList = FormatTreeUtils.listFormatTree(values, String.format("scheme_id_%s", key));
                treeNodeList.forEach(root -> SwitchTreeNode.calculateLeafSum(breakerSvgAfters, root, switchList));
            });
            // 防止重复数据的产生
            List<FhzgInfoBreakerSvgAfter> saveBreakerSvgAfters = breakerSvgAfters.stream().distinct().collect(Collectors.toList());
            if (ObjectUtils.isNotEmpty(saveBreakerSvgAfters)) {
                // 保存转供后的IPQ累加数据
                awaitTransferAreaResultMapper.saveBreakerSvgAfterBatch(saveBreakerSvgAfters);
            }
        }
    }

    /**
     * 获取预测数值指标值
     */
    private BigDecimal getMetricValue(MetricValueDTO device) {
        return Optional.ofNullable(device)
                .filter(d -> ObjectUtils.allNotNull(d, d.getValue()))
                .map(d -> BigDecimal.valueOf(d.getValue()))
                .orElse(null);
    }

    /**
     * 故障消息队列发送
     */
    private void sendRocketMQMessage(Long faultId) {
        try {
            // MQ消息订阅可以通过接口触发，当触发消息发送失败时不影响接口功能
            if (rocketMQProperties.getEnabled()) {
                RocketMQMessageEntity messageEntity = RocketMQMessageEntity.builder()
                        .topicId(RocketMQConstants.TOPIC_ID_FHZG_SCHEME_SCORE_RESULT_TICKET)
                        .cacheKey(RedisKeyConstants.ASYNC_QUEUE_SCHEME_SCORE_TICKET)
                        .tag("2")
                        .body(faultId).build();
                rocketMQTemplate.sendAsyncMessage(messageEntity);
            }
        } catch (Exception ex) {
            MessageRetryLog messageRetryLog = MessageRetryLog.builder().messageId(RocketMQConstants.TOPIC_ID_FHZG_SCHEME_SCORE_RESULT_TICKET)
                    .errorLog(ex.getMessage()).messageBody(String.valueOf(faultId)).cacheKey(RedisKeyConstants.ASYNC_QUEUE_SCHEME_SCORE_TICKET)
                    .tag("2").step(4).build();
            messageRetryLogService.saveLog(messageRetryLog);
            ex.printStackTrace();
        }
    }

    private void dealProtectionRecommend(List<XferSupplyAreaDTO> xferSupplyAreaList, Long schemeId) {
        Map<String, FhzgTransferSchemeSwitchProtectionRecommend> result = new HashMap<>();
        for (XferSupplyAreaDTO xferSupplyAreaDTO : xferSupplyAreaList) {
            List<FinalBreakerSafetyCheckResultDTO> breakerSafetyCheckResult = Optional.of(xferSupplyAreaDTO)
                    .map(XferSupplyAreaDTO::getFinalCheck)
                    .map(FinalCheckDTO::getBreakerSafetyCheckResult)
                    .orElse(new ArrayList<>());
            for (FinalBreakerSafetyCheckResultDTO finalBreakerSafetyCheckResultDTO : breakerSafetyCheckResult) {
                FhzgTransferSchemeSwitchProtectionRecommend recommend = new FhzgTransferSchemeSwitchProtectionRecommend();
                recommend.setPsrId(finalBreakerSafetyCheckResultDTO.getBreakerPSRID());
                recommend.setSchemeId(schemeId);
                recommend.setSwitchName(finalBreakerSafetyCheckResultDTO.getName());
                recommend.setCheckType(analysisTransferResultService.stringToInteger(finalBreakerSafetyCheckResultDTO.getCheckType()));
                recommend.setMaxAfter24hI(analysisTransferResultService.doubleToBigDecimal(finalBreakerSafetyCheckResultDTO.getMaxAfter24hI()));
                recommend.setRecommendOC3Value(analysisTransferResultService.doubleToBigDecimal(finalBreakerSafetyCheckResultDTO.getProtOverCurrent()));
                result.put(finalBreakerSafetyCheckResultDTO.getBreakerPSRID(), recommend);
            }
            List<FhzgTransferSchemeSwitchProtectionRecommend> protectionRecommendList = new ArrayList<>(result.values());
            protectionRecommendList.forEach(i -> {
                FhzgSwitchProtectionSettings switchProtectionSettings = switchProtectionSettingsService.getOne(new LambdaUpdateWrapper<FhzgSwitchProtectionSettings>()
                        .eq(FhzgSwitchProtectionSettings::getDevicePrsId, i.getPsrId()));
                if (switchProtectionSettings != null && switchProtectionSettings.getOc3Value() != null) {
                    i.setCurOC3Value(new BigDecimal(switchProtectionSettings.getOc3Value()));
                }
            });
            transferSchemeSwitchProtectionRecommendService.remove(new LambdaUpdateWrapper<FhzgTransferSchemeSwitchProtectionRecommend>()
                    .eq(FhzgTransferSchemeSwitchProtectionRecommend::getSchemeId, schemeId));
            transferSchemeSwitchProtectionRecommendService.saveBatch(protectionRecommendList);
        }
    }
}


