package com.hdkj.lt.mq.service.plan.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.aliyun.openservices.ons.api.bean.ProducerBean;
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.RedisKeyConstants;
import com.hdkj.lt.base.constants.RocketMQConstants;
import com.hdkj.lt.base.enums.EventTypeEnum;
import com.hdkj.lt.base.model.entity.FhzgBaseEntity;
import com.hdkj.lt.core.bizms.modle.dto.TransformerNameDTO;
import com.hdkj.lt.core.bizms.modle.po.FhzgDistTransformerCustomer;
import com.hdkj.lt.core.bizms.modle.po.FhzgSwitchProtectionSettings;
import com.hdkj.lt.core.bizms.modle.po.FhzgTransferSchemeSwitchProtectionRecommend;
import com.hdkj.lt.core.bizms.modle.po.MessageRetryLog;
import com.hdkj.lt.core.bizms.modle.po.fault.FaultOppositeLineCarryCapacity;
import com.hdkj.lt.core.bizms.modle.po.plan.*;
import com.hdkj.lt.core.bizms.modle.request.StateEstimationEquipRequest;
import com.hdkj.lt.core.hussar.SpringContextHolder;
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.MessageForPlanEntity;
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.FhzgPlanPowerCut;
import com.hdkj.lt.mq.entity.vo.FeederDeviceVO;
import com.hdkj.lt.mq.entity.vo.PlanPowerCutVO;
import com.hdkj.lt.mq.mapper.plan.FhzgPlanAnalyzeCalculateDecudeMapper;
import com.hdkj.lt.mq.mapper.plan.FhzgPlanSwitchInfoListMapper;
import com.hdkj.lt.mq.mapper.plan.PlanAwaitTransferAreaResultMapper;
import com.hdkj.lt.mq.mapper.plan.PlanPowerCutMapper;
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.plan.*;
import com.hdkj.lt.utils.tree.FormatTreeUtils;
import com.hdkj.hussar.ApiResponse;
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.ListUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.hdkj.lt.base.constants.CommonConstant.TWO;
import static com.hdkj.lt.mq.service.fault.impl.AnalysisFaultTransferResultServiceImpl.distinctByKey;

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

    private final PlanAwaitTransferAreaResultMapper awaitTransferAreaResultMapper;
    private final AnalysisPlanTransferSchemeService analysisPlanTransferSchemeService;
    private final FhzgPlanAnalyzeCalculateDecudeService fhzgPlanAnalyzeCalculateDecudeService;
    private final FhzgPlanAnalyzeCalculateDecudeMapper fhzgPlanAnalyzeCalculateDecudeMapper;
    private final PlanPowerCutMapper planPowerCutMapper;
    private final RocketMQProperties rocketMQProperties;
    private final RocketMQTemplate rocketMQTemplate;
    private final IMeasurementApiClient IMeasurementApiClient;
    private final MessageRetryLogService messageRetryLogService;
    private final FhzgOrganSuffixMapper fhzgOrganSuffixMapper;
    private final ISvgFileInfoService svgFileInfoService;
    private final FhzgPlanSwitchInfoListMapper planSwitchInfoListMapper;
    private final TransferSchemeSwitchProtectionRecommendService transferSchemeSwitchProtectionRecommendService;
    private final SwitchProtectionSettingsService switchProtectionSettingsService;
    private final IRefreshCacheApiClient refreshCacheApiClient;
    private final MultiThreadExecuteService multiThreadExecuteService;
    @Autowired(required = false)
    @Qualifier("buildProducer2")
    private ProducerBean producerBean;
    private final IPlanAwaitTransferUsersService awaitTransferUsersService;

//    private static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    /**
     * 获取计算推演平台计划转供结果
     *
     * @param planId
     * @return
     */
    public PlanPowerCutVO getTransferAreaResultByPlanId(@NotNull Long planId) {
        return awaitTransferAreaResultMapper.selectPlanAndPlanTime(planId);
    }

    /**
     * 保存计算推演平台计划转供结果
     */
    public void saveTransferAreaResult(Long planId, String transferAreaResult) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        PlanAwaitTransferAreaResultPO awaitTransferAreaResult = new PlanAwaitTransferAreaResultPO();
        awaitTransferAreaResult.setPlanId(planId).setTransferAreaJson(transferAreaResult).setCreateTime(LocalDateTime.now());
        Optional.ofNullable(loginUser).ifPresent(user -> awaitTransferAreaResult.setCreator(loginUser.getUserid()));
        awaitTransferAreaResultMapper.insert(awaitTransferAreaResult);
    }

    /**
     * 解析转供方案信息
     */
    public String analysisTransferResult(Long planId) {
        PlanPowerCutVO planAwaitTransferAreaResult = this.getTransferAreaResultByPlanId(planId);
        Assert.isTrue(ObjectUtils.isNotEmpty(planAwaitTransferAreaResult), "未发现计划停电信息或计划转供推演结果!");

        // 分时段查询设备状估数据入参
        StateEstimationEquipRequest stateEstimationEquip = StateEstimationEquipRequest.builder().psrType("dkx")
                .startTime(String.valueOf(planAwaitTransferAreaResult.getPeriodStartTime()))
                .endTime(String.valueOf(planAwaitTransferAreaResult.getPeriodEndTime())).build();

        // 故障馈线信息
        String linkLine = planAwaitTransferAreaResult.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.getOrganSuffixByPlanIdOrLineId(planId, null));
        feederTopoMapper.saveDistLineSwitchSection(linkLine, kgPsrType, pbPsrType);*/

        // 计划开始、结束时间
        LocalDateTime planStartTime = planAwaitTransferAreaResult.getPlanStartTime();
        LocalDateTime planEndTime = planAwaitTransferAreaResult.getPlanEndTime();
        AtomicBoolean flag = new AtomicBoolean(false);
        Optional.ofNullable(planAwaitTransferAreaResult.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<FhzgPlanAwaitTransferUsers> awaitTransferUsers = Lists.newArrayList();
                    // 对侧线路承载能力
                    List<FhzgPlanOppositeLineCarryCapacity> lineCarryCapacities = Lists.newArrayList();
                    // 转供方案路径信息
                    List<FhzgPlanTransferSchemePathDetail> schemePathDetails = Lists.newArrayList();
                    // 对侧线路负载率信息
                    List<FhzgPlanTransferSchemeOppositeLineLoadFactor> oppositeLineLoadFactors = Lists.newArrayList();
                    // 主变负载率信息
                    List<FhzgPlanTransferSchemePowerTransferInfo> powerTransferInfos = Lists.newArrayList();
                    // 对侧线路联络开关
                    List<FhzgPlanOppositeLineConcatSwitch> concatSwitchList = Lists.newArrayList();
                    // 可靠性校验转供用户信息(失电用户和不可转用户)
                    List<FhzgPlanTransferSchemeUsers> transferSchemeUsers = Lists.newArrayList();
                    // 转供方案可转用户
                    List<FhzgPlanTransferableSchemeUsers> transferableSchemeUsers = Lists.newArrayList();
                    Snowflake snowflake = IdUtil.getSnowflake(1, 1);
                    //转供前开关信息
                    LambdaQueryWrapper<FhzgPlanSwitchInfoList> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                    lambdaQueryWrapper.eq(FhzgPlanSwitchInfoList::getPlanId, planId);
                    List<FhzgPlanSwitchInfoList> list = planSwitchInfoListMapper.selectList(lambdaQueryWrapper);
                    if (!list.isEmpty()) {
                        planSwitchInfoListMapper.deleteBatchIds(list.stream().map(FhzgPlanSwitchInfoList::getId)
                                .collect(Collectors.toList()));
                    }
                    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));
                    planSwitchInfoListMapper.insert(FhzgPlanSwitchInfoList.builder()
                            .allSwitchInfoListJson(JSON.toJSONString(allSwitchInfoList)).feederCheckRuleJson(JSON.toJSONString(feederCheckRuleList))
                            .id(snowflake.nextId()).planId(planId).build());
                    //planPowerCutMapper.updateById(FhzgPlanPowerCut.builder().id(planId).allSwitchInfoListJson(JSON.toJSONString(allSwitchInfoList)).build());
                    // 待转供区域数据
                    List<SupplyAreaDTO> supplyAreaList = data.getSupplyAreaList();
                    // 保存开关段信息
                    fhzgPlanAnalyzeCalculateDecudeService.analyzeCalculateDecudeData(planId, supplyAreaList);
                    // 处理待转供用户
                    this.dealPlanAwaitTransferUsers(awaitTransferUsers, supplyAreaList, planId, linkLine, planStartTime, planEndTime);
                    // 转供方案组合
                    List<XferPlanDTO> xferPlanList = data.getXferPlanList();
                    flag.set(!xferPlanList.isEmpty());
                    try {
                        if (flag.get()) {
                            //设置额定电流
                            xferPlanList.forEach(e -> {
                                e.getXferSupplyAreaList().forEach(s -> {
                                    s.getLinkLineInfo().setRateCurrent(feederCheckRuleDTOMap
                                            .get(s.getLinkLineInfo().getPsrID()).getRateCurrent());
                                });
                            });
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    // 待转供对侧线路承载能力
                    this.dealPlanOppositeLineCarryCapacity(lineCarryCapacities, planId, xferPlanList, stateEstimationEquip,
                            feederCheckRuleDTOMap);
                    Map<Long, XferPlanDTO> xferPlanMap = MapUtil.newHashMap(); // 转供方案信息
                    AtomicReference<Integer> powerOnSuccess = new AtomicReference<>(0); // 方案是否可转供 0-false 1-true
                    xferPlanList.forEach(e -> {
                        e.setLoopCheckRule(data.getLoopCheckRule());
                        Long schemeId = snowflake.nextId(); // 转供方案ID
                        xferPlanMap.put(schemeId, e); // 转供方案组合信息
                        //动态切换表名，在dealPlanTransferSchemePathDetail方法外调用
                        //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByPlanIdOrLineId(planId, null));
                        //处理转供方案路径明细信息表
                        this.dealPlanTransferSchemePathDetail(schemePathDetails, e.getXferSupplyAreaList(), schemeId, linkLine, awaitTransferUsers, feederCheckRuleDTOMap);
                        //处理对侧线路负载率信息
                        this.dealPlanSchemeOppositeLineLoadFactor(oppositeLineLoadFactors, concatSwitchList, e.getXferSupplyAreaList(), schemeId, powerOnSuccess, feederCheckRuleDTOMap);
                        //处理主变负载率信息
                        this.dealPowerTransformerInfo(powerTransferInfos, e.getXferSupplyAreaList(), schemeId);
                        // 处理可靠性校验转供用户和可转供用户
                        this.dealPlanTransferSchemeUsers(transferSchemeUsers, transferableSchemeUsers, e.getXferSupplyAreaList(), schemeId, planStartTime, planEndTime);
                        // 处理保护定值推荐
                        this.dealProtectionRecommend(e.getXferSupplyAreaList(), schemeId);
                    });
                    // 更新计划停电方案是否可转供字段
                    planPowerCutMapper.updateById(FhzgPlanPowerCut.builder().powerOnSuccess(powerOnSuccess.get()).id(planId).build());
                    // 转供方案组合入库
                    analysisPlanTransferSchemeService.analysisPlanTransferScheme(planId, xferPlanMap, awaitTransferUsers);
                    // 待转供用户信息
                    Optional.of(awaitTransferUsers).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanAwaitTransferUsersService.class));
                    // 对侧线路承载能力
                    Optional.of(lineCarryCapacities).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanOppositeLineCarryCapacityService.class));
                    // 转供方案路径信息
                    Optional.of(schemePathDetails).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanTransferSchemePathDetailService.class));
                    // 对侧线路负载率信息
                    Optional.of(oppositeLineLoadFactors).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanSchemeOppositeLineLoadFactorService.class));
                    // 主变负载率信息
                    Optional.of(powerTransferInfos).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanTransferSchemePowerTransferInfoService.class));
                    // 可靠性校验转供用户信息
                    Optional.of(transferSchemeUsers).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanTransferSchemeUsersService.class));
                    // 可转供用户信息
                    Optional.of(transferableSchemeUsers).filter(ObjectUtils::isNotEmpty)
                            .ifPresent(en -> this.dynamicBatchSave(en, IPlanTransferableSchemeUsersService.class));

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

                    // 获取并设置方案对应的文件信息
                    xferPlanMap.forEach((key, val) -> {
                        LineFileInfoVO svgGenerationFile = new LineFileInfoVO();
                        try {
                            svgGenerationFile = svgFileInfoService.getSvgGenerationFile(linkLine, key, TWO);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        if (svgGenerationFile == null) {
                            ErrorLogParam errorLogParam = new ErrorLogParam()
                                    .setErrorTime(LocalDateTime.now())
                                    .setEventType(EventTypeEnum.TOPO_FILE.getCode())
                                    .setEventId(planId.toString())
                                    .setErrorCategory("方案文件绑定失败")
                                    .setErrorLevel("Warning")
                                    .setSourceSystem("2")
                                    .setOperationStep("计划方案成图")
                                    .setRelatedId(key.toString())
                                    .setStage("8")
                                    .setRelatedCategory("fhzg_plan_transfer_scheme")
                                    .setDetails("方案id：" + planId + "方案id：" + key + " 成图服务报错，请求参数: lineId:" + linkLine + ", objId" + key + ", type:" + TWO);
                            ExceptionErrorLogCast.cast(errorLogParam);
                        }
                    });
                });
        // MQ消息发送
        this.sendRocketMQMessage(planId, flag.get());
        // 生成动画反演数据
        CompletableFuture.runAsync(() -> refreshCacheApiClient.generateCartoonData(planId, "1"), multiThreadExecuteService.getExecutor());
        return ResultCode.SUCCESS.getMessage();
    }

    private void dealPowerTransformerInfo(List<FhzgPlanTransferSchemePowerTransferInfo> powerTransferInfos, List<XferSupplyAreaDTO> xferSupplyAreaList, Long schemeId) {
        List<FhzgPlanTransferSchemePowerTransferInfo> powerTransferInfoList = new ArrayList<>();
        xferSupplyAreaList.forEach(e -> {
            PowerTransformerInfoDTO powerTransformerInfo = e.getPowerTransformerInfo();
            if (powerTransformerInfo != null) {
                FhzgPlanTransferSchemePowerTransferInfo powerTransferInfo = new FhzgPlanTransferSchemePowerTransferInfo();
                powerTransferInfo.setSchemeId(schemeId);
                powerTransferInfo.setPowerTransformerId(powerTransformerInfo.getPowerTransformerId());
                powerTransferInfo.setPowerTransformerName(powerTransformerInfo.getPowerTransformerName());
                powerTransferInfo.setPowerTransformerPBefore(StringToBigDecimal(powerTransformerInfo.getPowerTransformerPBefore()));
                BigDecimal powerTransformerPAfter = StringToBigDecimal(powerTransformerInfo.getPowerTransformerPAfter());
                powerTransferInfo.setPowerTransformerPAfter(powerTransformerPAfter);
                powerTransferInfo.setXferSupplyAreaP(powerTransformerInfo.getXferSupplyAreaP());
                BigDecimal rateCapacity = StringToBigDecimal(powerTransformerInfo.getRateCapacity());
                powerTransferInfo.setRateCapacity(rateCapacity);
                powerTransferInfo.setVoltLevel(getVolLevelByEnum(powerTransformerInfo.getVoltLevel()));
                if (powerTransformerPAfter != null && rateCapacity != null && rateCapacity.compareTo(BigDecimal.valueOf(0)) != 0) {
                    powerTransferInfo.setLoadRate(powerTransformerPAfter.divide(rateCapacity, 5, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                }
                powerTransferInfoList.add(powerTransferInfo);
            }
        });
        powerTransferInfos.addAll(powerTransferInfoList);
    }

    private String getVolLevelByEnum(String volLevel) {
        switch (volLevel) {
            case "22":
                return "10";
            case "25":
                return "35";
            case "32":
                return "110";
            case "33":
                return "220";
        }
        return null;
    }


    /**
     * 处理待转供用户
     */
    private void dealPlanAwaitTransferUsers(List<FhzgPlanAwaitTransferUsers> dataList, List<SupplyAreaDTO> supplyAreaList,
                                            Long planId, String linkLine, LocalDateTime planStartTime, LocalDateTime planEndTime) {
        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());
                        FhzgPlanAwaitTransferUsers awaitTransferUser = new FhzgPlanAwaitTransferUsers();
                        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()))
                                .setPlanId(planId).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());
                        FhzgPlanAwaitTransferUsers awaitTransferUser = new FhzgPlanAwaitTransferUsers();
                        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()))
                                .setPlanId(planId).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.getOrganSuffixByPlanIdOrLineId(planId, null));
            // 根据psrId查询开关段
            List<FhzgPlanAwaitTransferSwitchSection> switchSectionL = fhzgPlanAnalyzeCalculateDecudeMapper.getSwitchSectionList(linkLine,
                    ListUtils.union(trans, customers), Arrays.asList(DictConstants.PB_PSR_TYPE.split(",")), planId);
            Map<String, FhzgPlanAwaitTransferSwitchSection> switchSectionMap = switchSectionL
                    .stream().collect(Collectors.toMap(k -> k.getPsrId(), v -> v));
            // 获取变压器用户的信息
            List<FhzgDistTransformerCustomer> transformerCustomer = awaitTransferAreaResultMapper.getTransformerCustomerInfo(trans, customers, planStartTime, planEndTime);
            Map<String, FhzgDistTransformerCustomer> customer = transformerCustomer.stream().collect(Collectors.toMap(FhzgDistTransformerCustomer::getTransformerNo, entity -> entity));
            dataList.forEach(e -> {
                FhzgPlanAwaitTransferSwitchSection awaitTransferSwitchSection = switchSectionMap.get(e.getTransformerNo());
                // 设置重要用户和敏感用户、所属开关段信息
                FhzgDistTransformerCustomer transUser = customer.get(e.getTransformerNo());
                e.setSwitchName(Optional.ofNullable(awaitTransferSwitchSection).map(en -> en.getStartSwitchName()).orElse(null))
                        .setSwitchId(Optional.ofNullable(awaitTransferSwitchSection).map(en -> en.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"));
            });
        }
    }

    //中压用户接入点名称改造
    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 dealPlanOppositeLineCarryCapacity(List<FhzgPlanOppositeLineCarryCapacity> dataList, Long planId,
                                                   List<XferPlanDTO> supplyAreaList, StateEstimationEquipRequest stateEstimationEquip,
                                                   Map<String, FeederCheckRuleDTO> feederCheckRuleDTOMap) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        List<FhzgPlanOppositeLineCarryCapacity> tempDataList = Lists.newArrayList();
        if (supplyAreaList == null || supplyAreaList.isEmpty()) {
            log.warn("无转供方案生成");
            return;
        }
        // 对侧线路承载能力数据
        supplyAreaList.forEach(e -> {
            LocalDateTime nowDateTime = LocalDateTime.now();
            // 转供方案的的对侧线路信息
            Optional.ofNullable(e.getXferSupplyAreaList())
                    .filter(ObjectUtils::isNotEmpty)
                    .ifPresent(en -> en.forEach(plan -> {
                        FhzgPlanOppositeLineCarryCapacity lineCarryCapacity = new FhzgPlanOppositeLineCarryCapacity();
                        Optional.ofNullable(plan.getLinkLineInfo()).ifPresent(line -> {
                            lineCarryCapacity.setLineId(Optional.ofNullable(line.getPsrID()).orElse(null))
                                    .setLineName(Optional.ofNullable(line.getName()).orElse(null))
                                    .setRatedCurrent(BigDecimal.valueOf(feederCheckRuleDTOMap.get(line.getPsrID()).getRateCurrent()))
                                    .setPlanId(planId).setCreateTime(nowDateTime);
                            Optional.ofNullable(loginUser).ifPresent(user -> lineCarryCapacity.setCreator(loginUser.getUserid()));
                            tempDataList.add(lineCarryCapacity);
                        });
                    }));
        });
        // 对侧线路承载能力的去重
        dataList.addAll(tempDataList.stream().filter(distinctByKey(FhzgPlanOppositeLineCarryCapacity::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();
        }
//        HashMap hashMap = new HashMap();
//        hashMap.put("15DKX-5837", new BigDecimal("160"));
//        lineIResp.setData(hashMap);
        //log.info("对侧线路七天最大电流map", lineIResp.getData());
        if (lineIResp.getCode() == ResultCode.SUCCESS.getCode() || ObjectUtils.isNotEmpty(lineIResp.getData())) {
            Map<String, BigDecimal> lineIMap = lineIResp.getData(); // 线路的七天最大电流值Map
            // 获取线路计算需要的电压依赖数据
            List<String> LineIds = dataList.stream().map(FhzgPlanOppositeLineCarryCapacity::getLineId).collect(Collectors.toList());
            //动态切换表名
            //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByPlanIdOrLineId(null, LineIds.get(0)));
            List<FeederDeviceVO> feederDeviceList = fhzgPlanAnalyzeCalculateDecudeMapper.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 = BigDecimal.valueOf(feederCheckRuleDTOMap.get((e.getLineId())).getRateCurrent());
//                BigDecimal maxCurrent = BigDecimal.valueOf(110.0);
//                BigDecimal ratedCurrent = BigDecimal.valueOf(108.0);
                if (ObjectUtils.allNotNull(maxCurrent, ratedCurrent)) {
                    BigDecimal maxLoadFactor;
                    // 最大负载率
                    if (ratedCurrent.compareTo(BigDecimal.valueOf(0)) == 0) {
                        maxLoadFactor = new BigDecimal("0");
                    } else {
                        maxLoadFactor = maxCurrent.divide(ratedCurrent, 4, RoundingMode.HALF_UP);
                    }
                    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));
                        }
                    }
                }
            });
        }
    }


    /**
     * 处理转供路径明细
     */
    private void dealPlanTransferSchemePathDetail(List<FhzgPlanTransferSchemePathDetail> dataList, List<XferSupplyAreaDTO> supplyAreaList,
                                                  Long schemeId, String lineId, List<FhzgPlanAwaitTransferUsers> awaitTransferUsers
            , Map<String, FeederCheckRuleDTO> feederCheckRuleDTOMap) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        supplyAreaList.forEach(e -> {
            List<String> userList = Lists.newArrayList();
            String startSwitchId = Optional.ofNullable(e.getIsolateBreaker()).map(en -> en.getBreakerPSRID()).orElse(null);
            String startSwitchName = Optional.ofNullable(e.getIsolateBreaker()).map(en -> en.getBreakerName()).orElse(null);
            // 对线线路存在时映射对应的值
            FhzgPlanTransferSchemePathDetail schemePathDetail = new FhzgPlanTransferSchemePathDetail();
            // 对侧线路
            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.getOrganSuffixByPlanIdOrLineId(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());
                }
            });
            // 取出本区域的所有的转供用户
            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.toString());
            // 开关段信息
            dataList.add(schemePathDetail);
        });
    }

    /**
     * 处理对侧线路负载率信息
     */
    private void dealPlanSchemeOppositeLineLoadFactor(List<FhzgPlanTransferSchemeOppositeLineLoadFactor> dataList, List<FhzgPlanOppositeLineConcatSwitch> switchList,
                                                      List<XferSupplyAreaDTO> supplyAreaList, Long schemeId, AtomicReference<Integer> powerOnSuccess
            , Map<String, FeederCheckRuleDTO> feederCheckRuleDTOMap) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        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 -> ObjectUtils.isNotEmpty(val.getI())).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 -> ObjectUtils.isNotEmpty(val.getI())).mapToDouble(val -> val.getI().getValue()).sum())
                    .orElse(0.0);
            // 对线线路存在时映射对应的值
            Optional.ofNullable(e.getLinkLineInfo()).ifPresent(linkLine -> {
                Long lineLoadFactorId = snowflake.nextId(); //对侧线路负载率ID
                FhzgPlanTransferSchemeOppositeLineLoadFactor oppositeLineLoadFactor = new FhzgPlanTransferSchemeOppositeLineLoadFactor();
                // 计算转供前对侧线路负载率
                //获取额定电流
                linkLine.setRateCurrent(feederCheckRuleDTOMap.get(linkLine.getPsrID()).getRateCurrent());
                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(100L))
                                .divide(BigDecimal.valueOf(linkLine.getRateCurrent()), 2, RoundingMode.HALF_UP))
                        .orElse(null);
                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))
                        .setRatedCurrent(Optional.ofNullable(linkLine.getRateCurrent()).map(BigDecimal::valueOf).orElse(null))
                        .setBeforeLoadFactor(beforeLoadFactor).setSchemeId(schemeId).setCreateTime(LocalDateTime.now()).setId(lineLoadFactorId);
                Optional.ofNullable(loginUser).ifPresent(user -> oppositeLineLoadFactor.setCreator(loginUser.getUserid()));
                dataList.add(oppositeLineLoadFactor);

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

    /**
     * 处理可靠性校验转供用户
     */
    private void dealPlanTransferSchemeUsers(List<FhzgPlanTransferSchemeUsers> dataList, List<FhzgPlanTransferableSchemeUsers> transferableUsers,
                                             List<XferSupplyAreaDTO> supplyAreaList, Long schemeId, LocalDateTime planStartTime, LocalDateTime planEndTime) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 可靠性校验转供用户数据
        List<String> trans = Lists.newArrayList();
        List<String> customers = Lists.newArrayList();
        List<FhzgPlanTransferSchemeUsers> 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());
                        FhzgPlanTransferSchemeUsers transferSchemeUser = new FhzgPlanTransferSchemeUsers();
                        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());
                        FhzgPlanTransferSchemeUsers transferSchemeUser = new FhzgPlanTransferSchemeUsers();
                        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, planStartTime, planEndTime);
            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); // 添加冷倒转的敏感或者重要失电用户
                }
                FhzgPlanTransferableSchemeUsers transferableUser = BeanUtil.copyProperties(e, FhzgPlanTransferableSchemeUsers.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 extends FhzgBaseEntity> void dynamicBatchSave(List<T> dataList, Class<? extends IService<T>> serviceClazz) {
        //todo:需要修改
//        HussarService hussarService = SpringContextHolder.getBean(serviceClazz);
//        hussarService.saveBatch(dataList);
        IService<T> service = SpringContextHolder.getBean(serviceClazz);
        service.saveBatch(dataList);
    }

    /**
     * 处理转供后 有功、无功、电流
     */
    private void dealFhzgInfoBreakerSvgAfter(String lineId, Long planId) {
        // 开关段类型
        List<String> switchList = Arrays.asList(DictConstants.KG_PSR_TYPE.split(","));
        // 配电类型
        List<String> transformerList = Arrays.asList(DictConstants.PB_PSR_TYPE.split(","));
        //动态切换表名
        //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByPlanIdOrLineId(planId, null));
        // 获取方案和开关用户信息
        List<SwitchTreeNode> treeNodes = awaitTransferAreaResultMapper.getBreakerSvgAfter(lineId, planId, 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 planId, Boolean flag) {
        //若有转供向计划停电发送MQ消息通知转供方案存在
        if (flag) {
            try {
                FhzgPlanPowerCut powerCut = planPowerCutMapper.selectById(planId);
                MessageForPlanEntity message = new MessageForPlanEntity();
                message.setMessageType("solution_created").setSourceSystem("jhtdwyy")
                        .setPlanNo(powerCut.getPlanNo()).setSolutionCreateTime(LocalDateTime.now())
                        .setPlanLastUpdateTime(powerCut.getCreateTime());
                if (rocketMQProperties.getEnabled()) {
                    RocketMQMessageEntity messageEntity = RocketMQMessageEntity.builder()
                            .topicId(RocketMQConstants.TOPIC_ID_SOLUTION_OPERATION_TICKET)
                            .cacheKey(RedisKeyConstants.ASYNC_QUEUE_SCHEME_SCORE_TICKET)
                            .tag("1")
                            .body(message).build();
                    com.aliyun.openservices.ons.api.Message message1 = buildMessage(messageEntity);
                    // log.info("计划停电消息推送：{}", JSON.toJSONString(message1));
                    message1.setTag("1");
                    message1.setTopic(RocketMQConstants.TOPIC_ID_SOLUTION_OPERATION_TICKET);
                    producerBean.sendAsync(message1, messageEntity.getSendCallback());
                    //rocketMQTemplate.sendAsyncMessage(messageEntity);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            try {
                //没有方案生成则发送方案生成失败消息
                FhzgPlanPowerCut powerCut = planPowerCutMapper.selectById(planId);
                MessageForPlanEntity message = new MessageForPlanEntity();
                message.setMessageType("solution_empty").setSourceSystem("jhtdwyy")
                        .setPlanNo(powerCut.getPlanNo()).setSolutionCreateTime(null)
                        .setPlanLastUpdateTime(powerCut.getCreateTime());
                if (rocketMQProperties.getEnabled()) {
                    RocketMQMessageEntity messageEntity = RocketMQMessageEntity.builder()
                            .topicId(RocketMQConstants.TOPIC_ID_SOLUTION_OPERATION_TICKET)
                            .cacheKey(RedisKeyConstants.ASYNC_QUEUE_SCHEME_SCORE_TICKET)
                            .tag("1")
                            .body(message).build();
                    com.aliyun.openservices.ons.api.Message message1 = buildMessage(messageEntity);
                    message1.setTag("1");
                    message1.setTopic(RocketMQConstants.TOPIC_ID_SOLUTION_OPERATION_TICKET);
                    producerBean.sendAsync(message1, messageEntity.getSendCallback());
                    //rocketMQTemplate.sendAsyncMessage(messageEntity);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        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("1")
                        .body(planId).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(planId)).cacheKey(RedisKeyConstants.ASYNC_QUEUE_SCHEME_SCORE_TICKET)
                    .tag("1").step(4).build();
            messageRetryLogService.saveLog(messageRetryLog);
            ex.printStackTrace();
        }
    }

    private com.aliyun.openservices.ons.api.Message buildMessage(RocketMQMessageEntity messageEntity) {
        com.aliyun.openservices.ons.api.Message message = new com.aliyun.openservices.ons.api.Message();
        Optional<RocketMQProperties.Topic> optional = rocketMQProperties.getTopic().stream().filter(e -> StringUtils.equals(e.getTopicId(), messageEntity.getTopicId())).findFirst();
        optional.ifPresent(e -> message.setTopic(e.getTopicName()));
        message.setTag(messageEntity.getTag());
        message.setBody(JSON.toJSONString(messageEntity.getBody()).getBytes(StandardCharsets.UTF_8));
        return message;
    }

    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<>());
            List<CbResultDTO> cbResult = Optional.of(xferSupplyAreaDTO)
                    .map(XferSupplyAreaDTO::getHotCheck)
                    .map(HotCheckDTO::getCbResult).orElse(new ArrayList<>());
            for (FinalBreakerSafetyCheckResultDTO finalBreakerSafetyCheckResultDTO : breakerSafetyCheckResult) {
                FhzgTransferSchemeSwitchProtectionRecommend recommend = new FhzgTransferSchemeSwitchProtectionRecommend();
                recommend.setPsrId(finalBreakerSafetyCheckResultDTO.getBreakerPSRID());
                recommend.setSchemeId(schemeId);
                recommend.setSwitchName(finalBreakerSafetyCheckResultDTO.getName());
                recommend.setCheckType(stringToInteger(finalBreakerSafetyCheckResultDTO.getCheckType()));
                recommend.setMaxAfter24hI(doubleToBigDecimal(finalBreakerSafetyCheckResultDTO.getMaxAfter24hI()));
                recommend.setRecommendOC3Value(doubleToBigDecimal(finalBreakerSafetyCheckResultDTO.getProtOverCurrent()));
                result.put(finalBreakerSafetyCheckResultDTO.getBreakerPSRID(), recommend);
            }
            for (CbResultDTO cbResultDTO : cbResult) {
                result.computeIfPresent(cbResultDTO.getPsrID(), (k, v) -> {
                    BigDecimal bigDecimal = doubleToBigDecimal(cbResultDTO.getLoopI());
                    if (bigDecimal != null) {
                        v.setLoopI(bigDecimal.abs().setScale(2, RoundingMode.HALF_UP));
                    }
                    return v;
                });
            }

            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);
        }
    }

    public Integer stringToInteger(String str) {
        if (str != null) {
            try {
                return Integer.parseInt(str);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    public BigDecimal doubleToBigDecimal(Double num) {
        if (num != null) {
            try {
                return new BigDecimal(num).setScale(2, RoundingMode.HALF_UP);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    public BigDecimal StringToBigDecimal(String num) {
        if (num != null) {
            try {
                return new BigDecimal(num).setScale(4, RoundingMode.HALF_UP);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

}


