package com.hdkj.lt.si.service.svg.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.hdkj.lt.base.constants.DictConstants;
import com.hdkj.lt.core.bizms.modle.dto.StateEstimation;
import com.hdkj.lt.core.bizms.modle.po.fault.FhzgDistLineSwitchSection;
import com.hdkj.lt.core.bizms.modle.request.StateEstimationRequest;
import com.hdkj.lt.core.plugins.thread.MultiThreadExecuteService;
import com.hdkj.lt.core.sys.dao.FhzgOrganSuffixMapper;
import com.hdkj.lt.feign.IFileApiClient;
import com.hdkj.lt.feign.IRefreshCacheApiClient;
import com.hdkj.lt.feign.ISvgGenerationApiClient;
import com.hdkj.lt.modle.FileInfoDTO;
import com.hdkj.lt.modle.FileRequest;
import com.hdkj.lt.modle.dto.file.LineSvgFileSaveDTO;
import com.hdkj.lt.modle.dto.svg.*;
import com.hdkj.lt.modle.po.DistLineSwitchStatusPO;
import com.hdkj.lt.modle.po.FhzgDistMappingFilePO;
import com.hdkj.lt.modle.vo.svg.DynamicSvgVO;
import com.hdkj.lt.modle.vo.svg.FeederBaseVO;
import com.hdkj.lt.modle.vo.svg.LineFileInfoVO;
import com.hdkj.lt.modle.vo.svg.StationFileInfoVO;
import com.hdkj.lt.si.dao.DistLineSwitchSectionMapper;
import com.hdkj.lt.si.dao.DistMappingFileMapper;
import com.hdkj.lt.si.modle.TransferSceneVO;
import com.hdkj.lt.si.service.estimation.StateEstimationService;
import com.hdkj.lt.si.service.svg.IDistLineSwitchSectionService;
import com.hdkj.lt.si.service.svg.ISvgGenerationService;
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.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
import static cn.hutool.core.date.DatePattern.PURE_DATE_PATTERN;
import static com.hdkj.lt.base.constants.CommonConstant.*;


/**
 * @Description
 * @Author wcx
 * @Date 2025/6/30 10:39
 * @Version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SvgGenerationServiceImpl implements ISvgGenerationService {

    private final IFileApiClient fileApiClient;

    private final ISvgGenerationApiClient svgGenerationApiClient;

    private final StateEstimationService stateEstimationService;

    private final DistMappingFileMapper distMappingFileMapper;

    private final IDistLineSwitchSectionService distLineSwitchSectionService;

    private final FhzgOrganSuffixMapper fhzgOrganSuffixMapper;

    private final IRefreshCacheApiClient refreshCacheApiClient;

    private final DistLineSwitchSectionMapper distLineSwitchSectionMapper;

    private final MultiThreadExecuteService multiThreadExecuteService;

    @Override
    public ApiResponse<List<LineFileInfoVO>> getAndSaveSvgGenerationByFeeder(SvgGenerationDTO svgGeneration) {
        List<LineFileInfoVO> listFileInfo = Lists.newArrayList();
        LocalDateTime currentTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);
        // 需要动态成图的线路
        List<String> feederList = svgGeneration.getFeederList();
        List<String> errorFeederList = Lists.newArrayList();

        if (ObjectUtils.isNotEmpty(feederList)) {
            feederList.forEach(feeder -> {
                List<FeederBaseVO> feederBaseList = Lists.newArrayList();
                // 线路下的事件场景对象
                SvgObjectDTO svgObject = Optional.ofNullable(svgGeneration.getSvgObject()).orElse(SvgObjectDTO.builder().build());
                if (StringUtils.equals(ONE, svgGeneration.getSvgType())) {
                    // 动态切换表名
                    //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByPsrIdOrFeeder(null, feeder));
                    // 批量获取线路的对侧线路和地市信息
                    feederBaseList.addAll(distMappingFileMapper.getDeviceInfoById(feeder));
                } else {
                    Assert.isTrue(ObjectUtils.isNotEmpty(svgObject.getObjId()), "场景ID和场景内容不允许为空!");
                    feederBaseList.addAll(distMappingFileMapper.getDeviceInfoByObjId(svgObject.getObjId(), svgObject.getObjType()));
                }
                // 对侧线路和地市信息转成HashMap
                Map<String, FeederBaseVO> feederMap = feederBaseList.stream().collect(Collectors.toMap(FeederBaseVO::getPsrId, e -> e));
                // 取主线路信息
                FeederBaseVO feederBase = feederMap.get(feeder);
                Assert.isTrue(ObjectUtils.isNotEmpty(feederBase), "主线路及所属地市信息不能为空");
                // 本侧和对侧所有线路ID集合
                List<String> lineIds = feederBaseList.stream().map(FeederBaseVO::getPsrId).collect(Collectors.toList());
                List<StateEstimation.StateEstimationSwitchResult> list = this.getStateEstimationResult(currentTime, lineIds);
                List<AppendSwitchDTO> fhdKgIds = Lists.newArrayList(); // 负荷点隐藏的开关信息
                DynamicSvgVO dynamicSvg = this.getDynamicSvgInfo(svgGeneration, feederBase, feederBaseList, list, fhdKgIds, null);
                if (ObjectUtils.isNotEmpty(dynamicSvg) && StringUtils.isNotEmpty(dynamicSvg.getSvgStr())) {
                    // 成图服务svg图的保存
                    LineSvgFileSaveDTO lineSvgFileSave = new LineSvgFileSaveDTO();
                    if (ObjectUtils.isNotEmpty(svgObject.getObjId())) {
                        lineSvgFileSave.setObjType(svgObject.getObjType()).setObjId(svgObject.getObjId());
                    }
                    lineSvgFileSave.setLineId(feeder).setFileName(feederBase.getName()).setFileContent(dynamicSvg.getSvgStr())
                            .setTopoVersion(currentTime.format(DateTimeFormatter.ofPattern(PURE_DATE_PATTERN)))
                            .setFileType(StringUtils.equalsAny(svgObject.getObjType(), FIVE, SIX) ? FIVE : FOUR);
                    listFileInfo.add(this.lineSvgFileSave(lineSvgFileSave).getData());
                    // 处理运行异常开关分合状态信息(目前只需要处理运行异常朝流问题)
                    Optional.ofNullable(svgGeneration).filter(e -> StringUtils.equals(TWO, e.getSvgType()))
                            .ifPresent(e -> this.dealDistLineSwitchStatus(list, svgObject.getObjId()));
                    // 保存成图返回的开关和字段数据内容
                    this.dealDistLineDynamicSvgDirectCurrent(dynamicSvg, Optional.ofNullable(svgObject.getObjId()).map(String::valueOf).orElse(feeder));
                    // 保存开关段信息，统计缩略图中隐藏的开关、公变、配变数量
                    distLineSwitchSectionService.saveLineSwitchSection(svgObject.getObjId(), feeder, dynamicSvg.getKgList());
                    // 需要获取负荷点隐藏开关并生成动态svg图，20250710添加逻辑
                    log.info("开始成负荷点详图");
                    this.dealLineSwitchSectionDetails(feeder, svgGeneration, feederBase, feederBaseList, list);
                } else {
                    // 添加异常线路的文件信息
                    errorFeederList.add(feeder);
                }
            });
            if (ObjectUtils.isNotEmpty(errorFeederList)) {
                String errorMsg = errorFeederList.stream().collect(Collectors.joining(","));
                throw new RuntimeException(String.format("调用服务获取动态SVG文件异常，【%s】未发现文件内容。", errorMsg));
            }
        }
        // 根据开关信息获取当前
        return ApiResponse.success(listFileInfo);
    }

    public ApiResponse<LineFileInfoVO> lineSvgFileSave(LineSvgFileSaveDTO lineSvgFile) {
        LineFileInfoVO lineFileInfo = BeanUtil.copyProperties(lineSvgFile, LineFileInfoVO.class);
        // SVG的byte数组
        FileRequest request = FileRequest.builder().fileName(lineSvgFile.getFileName()).fileContent(lineSvgFile.getFileContent()).build();
        FileInfoDTO fileInfo = Optional.ofNullable(fileApiClient.upload(request)).map(ApiResponse::getData).orElse(null);
        if (ObjectUtils.isNotEmpty(fileInfo) && StringUtils.isNotEmpty(fileInfo.getId())) {
            // 设置返回文件ID内容
            lineFileInfo.setFileId(Long.valueOf(fileInfo.getId()));
            // 计划方案、故障方案文件场景直接在方案入库时处理
            switch (lineSvgFile.getObjType()) {
                case ONE: // 计划文件场景
                    this.delPlanMappingFile(lineSvgFile, fileInfo.getId());
                    break;
                case TWO: // 计划方案文件场景
                    this.delPlanSchemeFile(lineSvgFile.getObjId(), fileInfo.getId());
                    break;
                case THREE: // 故障文件场景
                    this.delFaultMappingFile(lineSvgFile, fileInfo.getId());
                    break;
                case FOUR: // 故障文件场景
                    this.delFaultSchemeFile(lineSvgFile.getObjId(), fileInfo.getId());
                    break;
                case FIVE: // 运行调优场景
                    this.delOperationAbnormalityFile(lineSvgFile.getObjId(), fileInfo.getId());
                    break;
                case SIX: // 运行调优方案场景
                    this.delOperationAbnormalitySchemeFile(lineSvgFile.getObjId(), fileInfo.getId());
                    break;
                case SEVEN: //全口径低电压
                    this.delLimitMappingFile(lineSvgFile.getObjId(), fileInfo.getId());
                    break;
                case EIGHT: //全口径低电压方案
                    this.dealLimitSchemeFile(lineSvgFile.getObjId(), fileInfo.getId());
                default: // 线路文件场景
                    this.delDistMappingFile(lineSvgFile, fileInfo.getId());
                    break;
            }
        }
        return ApiResponse.success(lineFileInfo);
    }

    @Override
    public ApiResponse<String> allLineSvgFileSave(String cityShort) {
        List<String> lineList = distMappingFileMapper.getLineInfo(cityShort);
        CompletableFuture.runAsync(() -> {
            List<String> errorFile = Lists.newArrayList();
            lineList.forEach(line -> {
                try {
                    SvgGenerationDTO svgGeneration = new SvgGenerationDTO();
                    svgGeneration.setFeederList(Lists.newArrayList(line));
                    this.getAndSaveSvgGenerationByFeeder(svgGeneration);
                } catch (RuntimeException ex) {
                    errorFile.add(String.format("线路ID：【%s】异常信息：%s", line, ex.getMessage()));
                }
            });
            if (ObjectUtils.isNotEmpty(errorFile)) {
                throw new RuntimeException(JSON.toJSONString(errorFile));
            }
        }, multiThreadExecuteService.getExecutor());
        return ApiResponse.success(String.format("共【%s条】线路正生成SVG图...", lineList.size()));
    }

    @Override
    public ApiResponse<String> nonLineSceneSvgFileSave(String cityShort) {
        List<TransferSceneVO> sceneList = distMappingFileMapper.getNonLineSceneInfo(cityShort);
        CompletableFuture.runAsync(() -> {
            List<String> errorFile = Lists.newArrayList();
            sceneList.forEach(scene -> {
                try {
                    SvgGenerationDTO svgGeneration = new SvgGenerationDTO();
                    svgGeneration.setFeederList(Lists.newArrayList(scene.getLineId()));
                    svgGeneration.setSvgObject(SvgObjectDTO.builder().objId(scene.getObjId()).objType(scene.getObjType()).build());
                    this.getAndSaveSvgGenerationByFeeder(svgGeneration);
                } catch (RuntimeException ex) {
                    errorFile.add(String.format("线路ID：【%s-%s】异常信息：%s", scene.getLineId(), scene.getObjId(), ex.getMessage()));
                }
            });
            if (ObjectUtils.isNotEmpty(errorFile)) {
                throw new RuntimeException(JSON.toJSONString(errorFile));
            }
        }, multiThreadExecuteService.getExecutor());
        return ApiResponse.success(String.format("共【%s条】计划/故障/运行调优/方案等场景正生成SVG图...", sceneList.size()));
    }

    @Override
    public ApiResponse<String> lineSvgReset() {
        List<TransferSceneVO> svgResetList = distMappingFileMapper.getLineSvgResetInfo();
        CompletableFuture.runAsync(() -> {
            List<String> errorFile = Lists.newArrayList();
            svgResetList.forEach(reset -> {
                try {
                    SvgGenerationDTO svgGeneration = new SvgGenerationDTO();
                    svgGeneration.setFeederList(Lists.newArrayList(reset.getLineId()));
                    if (!StringUtils.equals(ZERO, reset.getObjType())) {
                        svgGeneration.setSvgObject(SvgObjectDTO.builder().objId(reset.getObjId()).objType(reset.getObjType()).build());
                    } else {
                        svgGeneration.setSvgObject(SvgObjectDTO.builder().build());
                    }
                    this.getAndSaveSvgGenerationByFeeder(svgGeneration);
                    distMappingFileMapper.updateLineSvgReset(reset.getLineId(), reset.getObjId(), reset.getObjType());
                } catch (RuntimeException ex) {
                    errorFile.add(String.format("线路ID：%s【%s-%s】异常信息：%s", reset.getLineId(), reset.getObjId(), reset.getObjType(), ex.getMessage()));
                }
            });
            if (ObjectUtils.isNotEmpty(errorFile)) {
                throw new RuntimeException(JSON.toJSONString(errorFile));
            }
        }, multiThreadExecuteService.getExecutor()).exceptionally(ex -> {
            ex.printStackTrace();
            return null;
        });

        return ApiResponse.success(String.format("共【%s条】需要重置的SVG图正在重置...", svgResetList.size()));
    }

    @Override
    public ApiResponse<List<StationFileInfoVO>> getAndSaveSvgGenerationByStation(StationSvgGenerationDTO stationSvgDTO) {
        List<StationFileInfoVO> stationFileInfo = Lists.newArrayList();
        // 当前时间 前2个小时 组成起止时间
        LocalDateTime currentTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);
        //
        // 变电站信息
        List<StationSvgObjectDTO> stationList = stationSvgDTO.getStationList();
        // 根据变电站获取对应的线路和联络开关信息
        List<String> stationIds = stationList.stream().map(StationSvgObjectDTO::getStation).collect(Collectors.toList());
        Map<String, List<StationDeviceDTO>> stationMap = distMappingFileMapper.getFeederAndSwitchInfoByStation(stationIds)
                .stream().collect(Collectors.groupingBy(StationDeviceDTO::getStation));
        stationList.forEach(station -> {
            // 每个变电站的设备信息
            List<StationDeviceDTO> stationDeviceList = stationMap.get(station.getStation());
            if (ObjectUtils.isNotEmpty(stationDeviceList)) {
                String stationName = stationDeviceList.get(0).getStationName(); // 变电站名称
                String feeder = stationDeviceList.get(0).getFeeder(); // 线路选第一条当本侧线路
                String cityId = stationDeviceList.get(0).getCity(); // 地市ID
                // 变电站成图的所有线路ID
                List<String> lineIds = stationDeviceList.stream().map(StationDeviceDTO::getFeeder).collect(Collectors.toList());
                List<StateEstimation.StateEstimationSwitchResult> list = this.getStateEstimationResult(currentTime, lineIds);

                // 20250826添加逻辑 - 自动化开关通过系统配置获取
                List<StateEstimation.StateEstimationSwitchResult> autoSwitchList = distMappingFileMapper.getAutoSwitchInfo(lineIds);
                // 自动化设备
                List<AutoDeviceDTO> autoDeviceList = autoSwitchList.stream()
                        .filter(e -> StringUtils.isNotEmpty(e.getFeederId()) && StringUtils.equals(e.getIsAuto(), ONE))
                        .map(e -> AutoDeviceDTO.builder().sbId(e.getPsrId()).sbType(ONE).xlId(e.getFeederId()).build())
                        .distinct().collect(Collectors.toList());

                // 非主站有效联络开关的线路 及 主站的所有线路
                List<String> normalFeederList = stationDeviceList.stream()
                        .filter(e -> StringUtils.equals(ONE, e.getStationType()) || StringUtils.equals("valid", e.getSwitchState()))
                        .map(StationDeviceDTO::getFeeder).distinct().collect(Collectors.toList());
                // 对侧其他联络线路 (比较特殊这里根据有效联络线路在筛选一次联络线路)
                List<String> otherLines = lineIds.stream().filter(e -> !StringUtils.equals(e, feeder))
                        .filter(e -> normalFeederList.contains(e)).distinct().collect(Collectors.toList());

                // 有效联络开关ID
                List<String> normalKgList = stationDeviceList.stream()
                        .filter(e -> StringUtils.equals("valid", e.getSwitchState()))
                        .map(StationDeviceDTO::getPsrId).distinct().collect(Collectors.toList());
                // 无效联络开关ID
                List<String> invalidKgList = stationDeviceList.stream()
                        .filter(e -> StringUtils.equals("invalid", e.getSwitchState()))
                        .map(StationDeviceDTO::getPsrId).distinct().collect(Collectors.toList());
                // 无效的联络开关和所属线路的信息， 成图需要把无效联络对应两条线路组成两个开关线路数据
                Map<String, List<String>> invalidKgFeederMap = stationDeviceList.stream()
                        .filter(e -> StringUtils.equals("invalid", e.getSwitchState()))
                        .collect(Collectors.groupingBy(e -> e.getPsrId(), Collectors.mapping(e -> e.getFeeder(), Collectors.toList())));
                // 动态获取SVG图的参数
                DynamicSvgDetailDTO dynamicSvgDetail = DynamicSvgDetailDTO.builder()
                        .xlId(feeder).city(cityId).zdhSbList(autoDeviceList)
                        .otherXlIds(otherLines).llKgIds(normalKgList).build();
                // 需要显示的其他开关
                List<AppendSwitchDTO> switchList = Lists.newArrayList();
                // 通过状估接口的分合状态估计值量测值 来确定 其他开关（包含所有分位开关和合位的无效联络开关）/* 这里默认无分开关 */
                switchList.addAll(list.stream()
                        .filter(e -> StringUtils.isNotEmpty(e.getFeederId()) && (/*StringUtils.equals(e.getSeoStatuss().get(0), ZERO)
                                || */(StringUtils.equals(e.getSeoStatuss().get(0), ONE) && invalidKgList.contains(e.getPsrId()))))
                        .flatMap(e -> {
                            List<String> feederList = invalidKgFeederMap.get(e.getPsrId());
                            if (ObjectUtils.isNotEmpty(feederList)) {
                                return feederList.stream()
                                        .map(en -> AppendSwitchDTO.builder().xlId(en).kgId(e.getPsrId()).build())
                                        .collect(Collectors.toList()).stream();
                            } else {
                                return Stream.of(AppendSwitchDTO.builder().xlId(e.getFeederId()).kgId(e.getPsrId()).build());
                            }
                        }).distinct().collect(Collectors.toList()));

                Optional.ofNullable(switchList).filter(ObjectUtils::isNotEmpty).ifPresent(en -> dynamicSvgDetail.setOtherKgList(en));

                String objId = station.getStation(); // todo 目前暂时使用变电站ID
                String switchId = station.getStartKgId(); // 起点开关信息
                String parameterInfo1 = JSON.toJSONString(dynamicSvgDetail);
                log.info("变电站动态成图详图服务调用参数-事件：{}", parameterInfo1);
                // 调用成图服务获取信息
                DynamicSvgVO dynamicSvg1 = svgGenerationApiClient.queryDynamicSvgDetail(dynamicSvgDetail).getData();
                this.dealDistDynamicSvgParameter(objId, "7", null, parameterInfo1, dynamicSvg1);

                // ==========>>>>>>>>>> 20250815 临时方案(这里生成四个图) <<<<<<<<<<==========
                // 负荷点开关
                List<String> kgPsrTypes = Arrays.asList(DictConstants.KG_PSR_TYPE.split(","));
                String endKgId = Optional.ofNullable(station.getEndKgId()).orElse("-");
                List<LineDeviceDTO> deviceList = distMappingFileMapper.getLineSwitchSectionDetails(station.getStartKgId(), endKgId, kgPsrTypes);
                List<AppendSwitchDTO> appendSwitchList = deviceList.stream().map(e -> AppendSwitchDTO.builder().xlId(e.getFeeder()).kgId(e.getPsrId()).build()).collect(Collectors.toList());

                // 事件负荷点
                List<AppendSwitchDTO> fhdSwitchList = Lists.newArrayList(switchList);
                fhdSwitchList.addAll(appendSwitchList);
                Optional.ofNullable(fhdSwitchList).filter(ObjectUtils::isNotEmpty).ifPresent(en -> dynamicSvgDetail.setOtherKgList(en));
                String parameterInfo3 = JSON.toJSONString(dynamicSvgDetail);
                log.info("变电站动态成图详图服务调用参数-事件负荷点：{}", parameterInfo3);
                // 调用成图服务获取信息
                DynamicSvgVO dynamicSvg3 = svgGenerationApiClient.queryDynamicSvgDetail(dynamicSvgDetail).getData();
                this.dealDistDynamicSvgParameter(objId, "7", switchId, parameterInfo3, dynamicSvg3);
                stationFileInfo.add(this.dealStationDynamicSvg("SJT", station.getStation(), stationName, dynamicSvg1));
                stationFileInfo.add(this.dealStationDynamicSvg("SJFHD", station.getStation(), stationName, dynamicSvg3));

                List<List<JSONObject>> kgOpsLists = station.getKgOpsList();
                for (int i = 0; i < kgOpsLists.size(); i++) {
                    // 方案图, 分位的开关和合位开关
                    List<JSONObject> kgOpsList = kgOpsLists.get(i);
                    List<AppendSwitchDTO> faSwitchList = Lists.newArrayList(switchList);
                    faSwitchList.addAll(kgOpsList.stream()
                            .filter(e -> StringUtils.equalsAny(e.getStr("operationContent"), "0", "1"))
                            .map(e -> AppendSwitchDTO.builder().xlId(e.getStr("lineId")).kgId(e.getStr("switchId")).build()).collect(Collectors.toList()));
                    Optional.ofNullable(faSwitchList).filter(ObjectUtils::isNotEmpty).ifPresent(en -> dynamicSvgDetail.setOtherKgList(en));
                    String parameterInfo2 = JSON.toJSONString(dynamicSvgDetail);

                    log.info("变电站动态成图详图服务调用参数-方案：{}", parameterInfo2);
                    // 调用成图服务获取信息
                    DynamicSvgVO dynamicSvg2 = svgGenerationApiClient.queryDynamicSvgDetail(dynamicSvgDetail).getData();
                    this.dealDistDynamicSvgParameter(String.format("%s-%s", objId, i + 1), "8", null, parameterInfo2, dynamicSvg2);

                    // 方案负荷点
                    faSwitchList.addAll(appendSwitchList);
                    Optional.ofNullable(faSwitchList).filter(ObjectUtils::isNotEmpty).ifPresent(en -> dynamicSvgDetail.setOtherKgList(en));
                    String parameterInfo4 = JSON.toJSONString(dynamicSvgDetail);

                    log.info("变电站动态成图详图服务调用参数-方案负荷点：{}", parameterInfo4);
                    // 调用成图服务获取信息
                    DynamicSvgVO dynamicSvg4 = svgGenerationApiClient.queryDynamicSvgDetail(dynamicSvgDetail).getData();
                    this.dealDistDynamicSvgParameter(String.format("%s-%s", objId, i + 1), "8", switchId, parameterInfo4, dynamicSvg4);

                    stationFileInfo.add(this.dealStationDynamicSvg(String.format("FAT%s", (i + 1)), station.getStation(), stationName, dynamicSvg2));
                    stationFileInfo.add(this.dealStationDynamicSvg(String.format("FAFHD%s", (i + 1)), station.getStation(), stationName, dynamicSvg4));
                }
            }
        });

        return ApiResponse.success(stationFileInfo);
    }

    /**
     * 处理变电站动态成图
     */
    private StationFileInfoVO dealStationDynamicSvg(String type, String stationId, String stationName, DynamicSvgVO dynamicSvg) {
        StationFileInfoVO stationFileInfo = new StationFileInfoVO();
        stationFileInfo.setFileType(type);
        stationFileInfo.setStationId(stationId);
        stationFileInfo.setTopoVersion(LocalDate.now().format(DateTimeFormatter.ofPattern(PURE_DATE_PATTERN)));
        if (ObjectUtils.isNotEmpty(dynamicSvg) && StringUtils.isNotEmpty(dynamicSvg.getSvgStr())) {
            FileRequest request = FileRequest.builder().fileName(stationName).fileContent(dynamicSvg.getSvgStr()).build();
            FileInfoDTO fileInfo = Optional.ofNullable(fileApiClient.upload(request)).map(ApiResponse::getData).orElse(null);
            if (ObjectUtils.isNotEmpty(fileInfo) && StringUtils.isNotEmpty(fileInfo.getId())) {
                // 设置返回文件ID内容
                stationFileInfo.setFileId(Long.valueOf(fileInfo.getId()));
            }
        }
        return stationFileInfo;
    }


    /**
     * 获取动态svg图信息
     */
    private DynamicSvgVO getDynamicSvgInfo(SvgGenerationDTO svgGeneration, FeederBaseVO feederBase, List<FeederBaseVO> feederList,
                                           List<StateEstimation.StateEstimationSwitchResult> list, List<AppendSwitchDTO> details, String switchId) {
        String appendLogInfo = Optional.ofNullable(details).filter(ObjectUtils::isNotEmpty).map(e -> "-负荷点").orElse("");
        SvgObjectDTO svgObject = Optional.ofNullable(svgGeneration.getSvgObject()).orElse(SvgObjectDTO.builder().build());
        String feeder = feederBase.getPsrId(); // 主线路ID
        String objId = Optional.ofNullable(svgObject.getObjId()).map(String::valueOf).orElse(feeder); // 动态成图参数关联ID
        String objType = Optional.ofNullable(svgObject.getObjType()).orElse(ZERO); // 动态成图参数关联类型
        // 20250826添加逻辑 - 自动化开关通过系统配置获取
        List<String> lineIds = feederList.stream().map(FeederBaseVO::getPsrId).collect(Collectors.toList());
        List<StateEstimation.StateEstimationSwitchResult> autoSwitchList = distMappingFileMapper.getAutoSwitchInfo(lineIds);
        // 自动化设备信息
        List<AutoDeviceDTO> autoDeviceList = autoSwitchList.stream()
                .filter(e -> StringUtils.isNotEmpty(e.getFeederId()) && StringUtils.equals(e.getIsAuto(), ONE))
                .map(e -> AutoDeviceDTO.builder().sbId(e.getPsrId()).sbType(ONE).xlId(e.getFeederId()).build())
                .distinct().collect(Collectors.toList());

        // 20250807 添加逻辑 需要获取联络开关信息（有效联络和无效联络）
        List<String> feederIdList = Lists.newArrayList();
        if (StringUtils.equals(ONE, svgGeneration.getSvgType())) {
            feederIdList.add(feeder); // 计划、故障仅需要主线ID
        } else {
            feederIdList.addAll(lineIds); // 运行调优需要展示所有线路ID
        }
        Map<String, List<LineDeviceDTO>> deviceTypeMap = distMappingFileMapper.getTieSwitchInfoByFeeder(feederIdList)
                .stream().collect(Collectors.groupingBy(LineDeviceDTO::getSwitchState));
        // 无效的联络开关信息
        List<String> invalidKgList = Optional.ofNullable(deviceTypeMap.get("invalid"))
                .map(e -> e.stream().map(LineDeviceDTO::getPsrId).distinct().collect(Collectors.toList()))
                .orElse(Lists.newArrayList());
        // 有效联络开关ID
        List<String> normalKgList = Optional.ofNullable(deviceTypeMap.get("valid"))
                .map(e -> e.stream().map(LineDeviceDTO::getPsrId).distinct().collect(Collectors.toList()))
                .orElse(Lists.newArrayList());
        // 无效的联络开关和所属线路的信息， 成图需要把无效联络对应两条线路组成两个开关线路数据
        Map<String, List<String>> invalidKgFeederMap = Optional.ofNullable(deviceTypeMap.get("invalid"))
                .map(e -> e.stream().collect(Collectors.groupingBy(en -> en.getPsrId(), Collectors.mapping(en -> en.getFeeder(), Collectors.toList()))))
                .orElse(MapUtil.newHashMap());

        // 负荷点隐藏开关不为空时，添加到otherKgList中显示
        List<AppendSwitchDTO> switchList = Lists.newArrayList();
        Optional.ofNullable(details).filter(ObjectUtils::isNotEmpty).ifPresent(en -> switchList.addAll(en));
        DynamicSvgVO dynamicSvgInfo; // 调用动态成图结果返回结果信息
        if (StringUtils.equals(ONE, svgGeneration.getSvgType())) {
            // 动态获取SVG图的参数
            DynamicSvgDTO dynamicSvgDTO = DynamicSvgDTO.builder()
                    .xlId(feeder).ctType(svgGeneration.getSvgType()).llKgIds(normalKgList)
                    .city(feederBase.getCity()).zdhSbList(autoDeviceList).build();

            // 获取计划、计划方案、故障、故障方案的额外开关（20250811添加合环、终态校验不通过的开关）
            if (ObjectUtils.isNotEmpty(svgObject) && ObjectUtils.isNotEmpty(svgObject.getObjId())) {
                // 需要保留的额外的开关列表
                switchList.addAll(this.getAppendSwitchList(svgObject.getObjId(), svgObject.getObjType()));
            }
            Optional.ofNullable(switchList).filter(ObjectUtils::isNotEmpty).ifPresent(en -> dynamicSvgDTO.setOtherKgList(en));
            String parameterInfo = JSON.toJSONString(dynamicSvgDTO);
            log.info("动态成图简图服务{}调用参数：{}", appendLogInfo, parameterInfo);
            // 调用成图服务获取信息
            dynamicSvgInfo = svgGenerationApiClient.queryDynamicSvg(dynamicSvgDTO).getData();
            this.dealDistDynamicSvgParameter(objId, objType, switchId, parameterInfo, dynamicSvgInfo);
        } else {
            // 对侧其他联络线路
            List<String> otherLines = feederList.stream()
                    .filter(e -> !StringUtils.equals(e.getPsrId(), feeder))
                    .map(FeederBaseVO::getPsrId).collect(Collectors.toList());
            // 通过状估接口的分合状态估计值量测值 来确定 其他开关（包含所有分位开关和合位的无效联络开关）
            switchList.addAll(list.stream()
                    .filter(e -> StringUtils.isNotEmpty(e.getFeederId()) && (StringUtils.equals(e.getSeoStatuss().get(0), ZERO)
                            || (StringUtils.equals(e.getSeoStatuss().get(0), ONE) && invalidKgList.contains(e.getPsrId()))))
                    .flatMap(e -> {
                        List<String> invalidFeederList = invalidKgFeederMap.get(e.getPsrId());
                        if (ObjectUtils.isNotEmpty(invalidFeederList)) {
                            return invalidFeederList.stream()
                                    .map(en -> AppendSwitchDTO.builder().xlId(en).kgId(e.getPsrId()).build())
                                    .collect(Collectors.toList()).stream();
                        } else {
                            return Stream.of(AppendSwitchDTO.builder().xlId(e.getFeederId()).kgId(e.getPsrId()).build());
                        }
                    }).distinct().collect(Collectors.toList()));

            if (StringUtils.equals(svgObject.getObjType(), SIX)) {
                // 动态切换表名
                //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByPsrIdOrFeeder(null, feeder));
                // 获取运行调优的开关动作的 分位开关和合位开关
                List<LineDeviceDTO> lineDevices = distMappingFileMapper.getLineSwitchInfo(svgObject.getObjId());
                // 调优方案开关动作中，分位的开关和合位的开关
                switchList.addAll(lineDevices.stream()
                        .filter(e -> StringUtils.equalsAnyIgnoreCase(e.getSwitchState(), "open", "close"))
                        .map(e -> AppendSwitchDTO.builder().xlId(e.getFeeder()).kgId(e.getPsrId()).build()).collect(Collectors.toList()));
            }
            // 动态获取SVG图的参数
            DynamicSvgDetailDTO dynamicSvgDetail = DynamicSvgDetailDTO.builder()
                    .xlId(feeder).city(feederBase.getCity()).zdhSbList(autoDeviceList)
                    .otherXlIds(otherLines).llKgIds(normalKgList).build();
            Optional.ofNullable(switchList).filter(ObjectUtils::isNotEmpty).ifPresent(en -> dynamicSvgDetail.setOtherKgList(en));

            String parameterInfo = JSON.toJSONString(dynamicSvgDetail);
            log.info("动态成图详图{}服务调用参数：{}", appendLogInfo, parameterInfo);
            // 调用成图服务获取信息
            dynamicSvgInfo = svgGenerationApiClient.queryDynamicSvgDetail(dynamicSvgDetail).getData();
            this.dealDistDynamicSvgParameter(objId, objType, switchId, parameterInfo, dynamicSvgInfo);
        }
        return dynamicSvgInfo;
    }

    /**
     * 需要获取负荷点隐藏开关并生成动态svg图
     */
    private void dealLineSwitchSectionDetails(String feeder, SvgGenerationDTO svgGeneration, FeederBaseVO feederBase,
                                              List<FeederBaseVO> feederList, List<StateEstimation.StateEstimationSwitchResult> list) {
        List<String> kgPsrTypes = Arrays.asList(DictConstants.KG_PSR_TYPE.split(","));
        // 线路下的事件场景对象
        SvgObjectDTO svgObject = Optional.ofNullable(svgGeneration.getSvgObject()).orElse(SvgObjectDTO.builder().build());
        List<AppendDeviceDTO> deviceList = distLineSwitchSectionService.getLineSwitchSectionDetails(svgObject.getObjId(), feeder, kgPsrTypes);
        // 分组所属开关开关信息
        Map<String, List<AppendDeviceDTO>> deviceMap = deviceList.stream().collect(Collectors.groupingBy(AppendDeviceDTO::getSwitchId));
        List<String> errorFeederList = Lists.newArrayList();
        List<FhzgDistLineSwitchSection> switchSectionList = Lists.newArrayList();
        // 根据每个负荷所属开关生成不同的动态图
        deviceMap.forEach((switchId, subList) -> {
            // 负荷点隐藏的开关
            List<AppendSwitchDTO> kgList = subList.stream().map(e -> AppendSwitchDTO.builder().xlId(feeder).kgId(e.getPsrId()).build()).collect(Collectors.toList());
            Optional.ofNullable(kgList).filter(ObjectUtils::isNotEmpty).ifPresent(entity -> {
                DynamicSvgVO dynamicSvg = this.getDynamicSvgInfo(svgGeneration, feederBase, feederList, list, entity, switchId);
                if (ObjectUtils.isNotEmpty(dynamicSvg) && StringUtils.isNotEmpty(dynamicSvg.getSvgStr())) {
                    // 成图服务svg图的保存
                    FileRequest request = FileRequest.builder().fileName(feederBase.getName()).fileContent(dynamicSvg.getSvgStr()).build();
                    FileInfoDTO fileInfo = Optional.ofNullable(fileApiClient.upload(request)).map(ApiResponse::getData).orElse(null);
                    FhzgDistLineSwitchSection switchSection = new FhzgDistLineSwitchSection();
                    // 根据分组规则，获取所属开关的开关段表ID
                    switchSection.setId(subList.get(0).getKgdId()).setFileId(Long.valueOf(fileInfo.getId()));
                    switchSectionList.add(switchSection);
                } else {
                    // 添加负荷点所属开关信息
                    errorFeederList.add(switchId);
                }
            });
        });
        // 批量保存已经生成的负荷点详情svg图的文件ID
        Optional.ofNullable(switchSectionList).filter(ObjectUtils::isNotEmpty).ifPresent(e -> distLineSwitchSectionMapper.batchUpdateFileIds(e));

        if (ObjectUtils.isNotEmpty(errorFeederList)) {
            String errorMsg = errorFeederList.stream().collect(Collectors.joining(","));
            throw new RuntimeException(String.format("调用服务获取场景动态SVG文件成功，负荷点动态SVG文件异常，【%s】未发现负荷点所属开关文件内容。", errorMsg));
        }
    }

    /**
     * 其他图上需要保留开关列表
     */
    private List<AppendSwitchDTO> getAppendSwitchList(Long objId, String objType) {
        Assert.isTrue(ObjectUtils.allNotNull(objId, objType), "追加开关的代理主键和场景类型不能为空。");
        List<AppendSwitchDTO> switchIdInfo = distMappingFileMapper.getSwitchInfoById(objId, objType);
        Assert.isTrue(ObjectUtils.isNotEmpty(switchIdInfo), "未找到追加开关，请检查代理主键和场景类型。");
        // 拆解根据线路分组的开关ID信息
        List<AppendSwitchDTO> appendSwitchList = Lists.newArrayList();
        switchIdInfo.stream().filter(e -> StringUtils.isNotEmpty(e.getKgId()))
                .forEach(e -> appendSwitchList.addAll(Arrays.stream(e.getKgId().split(",")).distinct()
                        .map(en -> AppendSwitchDTO.builder().xlId(e.getXlId()).kgId(en).build()).collect(Collectors.toList())
                ));
        return appendSwitchList;
    }

    /**
     * 线路文件场景保存
     */
    private void delDistMappingFile(LineSvgFileSaveDTO lineSvgFile, String fileId) {
        // 先删除线路文件信息
        LambdaQueryWrapper<FhzgDistMappingFilePO> queryWrapper = new LambdaQueryWrapper<FhzgDistMappingFilePO>()
                .eq(FhzgDistMappingFilePO::getLineId, lineSvgFile.getLineId())
                .eq(FhzgDistMappingFilePO::getFileType, lineSvgFile.getFileType());
        distMappingFileMapper.delete(queryWrapper);
        // 保存文件信息到线路文件业务表
        FhzgDistMappingFilePO distMappingFile = this.getDistMappingFile(lineSvgFile, fileId);
        distMappingFileMapper.insert(distMappingFile);
        // 线路信息缓存刷新
        this.fileUpdateRefreshAllFeederCache(lineSvgFile.getLineId());
    }

    /**
     * 计划文件场景保存
     */
    private void delPlanMappingFile(LineSvgFileSaveDTO lineSvgFile, String fileId) {
        // 先删除计划文件信息
        distMappingFileMapper.deletePlanDistMappingFile(lineSvgFile.getObjId(), lineSvgFile.getFileType());
        // 保存文件信息到计划文件业务表
        FhzgDistMappingFilePO distMappingFile = this.getDistMappingFile(lineSvgFile, fileId);
        distMappingFileMapper.savePlanDistMappingFile(distMappingFile, lineSvgFile.getObjId());
    }

    /**
     * 计划方案文件场景保存
     */
    private void delPlanSchemeFile(Long schemeId, String fileId) {
        // 修改计划方案的文件内容
        distMappingFileMapper.updatePlanSchemeFileIdById(schemeId, fileId);
    }

    /**
     * 故障文件场景保存
     */
    private void delFaultMappingFile(LineSvgFileSaveDTO lineSvgFile, String fileId) {
        // 先删除故障文件信息
        distMappingFileMapper.deleteFaultDistMappingFile(lineSvgFile.getObjId(), lineSvgFile.getFileType());
        // 保存文件信息到故障文件业务表
        FhzgDistMappingFilePO distMappingFile = this.getDistMappingFile(lineSvgFile, fileId);
        distMappingFileMapper.saveFaultDistMappingFile(distMappingFile, lineSvgFile.getObjId());
    }

    /**
     * 故障方案场景保存
     */
    private void delFaultSchemeFile(Long schemeId, String fileId) {
        // 修改故障方案的文件内容
        distMappingFileMapper.updateFaultSchemeFileIdById(schemeId, fileId);
    }

    /**
     * 运行异常场景保存
     */
    private void delOperationAbnormalityFile(Long oaId, String fileId) {
        // 修改运行异常的文件内容
        distMappingFileMapper.updateOperationAbnormalityFileIdById(oaId, fileId);
    }

    /**
     * 运行异常方案场景保存
     */
    private void delOperationAbnormalitySchemeFile(Long schemeId, String fileId) {
        // 修改运行异常方案的文件内容
        distMappingFileMapper.updateOperationAbnormalitySchemeFileIdById(schemeId, fileId);
    }

    private void dealLimitSchemeFile(Long schemeId, String fileId) {
        distMappingFileMapper.updateLimitSchemeFileFileIdById(schemeId, fileId);
    }

    private void delLimitMappingFile(Long schemeId, String fileId) {
        distMappingFileMapper.updateLimitFileFileIdById(schemeId, fileId);
    }

    /**
     * 获取配电成图文件关联信息
     */
    private FhzgDistMappingFilePO getDistMappingFile(LineSvgFileSaveDTO lineSvgFile, String fileId) {
        FhzgDistMappingFilePO distMappingFile = BeanUtil.copyProperties(lineSvgFile, FhzgDistMappingFilePO.class);
        distMappingFile.setFileId(Long.valueOf(fileId));
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Optional.ofNullable(loginUser).ifPresent(user -> distMappingFile.setCreator(user.getUserid()).setCreateTime(LocalDateTime.now()));
        return distMappingFile;
    }

    /**
     * 动态成图结果保存
     */
    private void dealDistLineDynamicSvgDirectCurrent(DynamicSvgVO dynamicSvg, String objId) {
        CompletableFuture.runAsync(() -> {
            String clJsonStr = JSON.toJSONString(Optional.ofNullable(dynamicSvg.getClList()).orElse(Lists.newArrayList()));
            String kgJsonStr = JSON.toJSONString(Optional.ofNullable(dynamicSvg.getKgList()).orElse(Lists.newArrayList()));
            // 先删后增动态成图返回信息
            distMappingFileMapper.deleteDistLineDynamicSvgDirectCurrent(objId);
            distMappingFileMapper.saveDistLineDynamicSvgDirectCurrent(clJsonStr, kgJsonStr, objId);
        }, multiThreadExecuteService.getExecutor());
    }

    /**
     * 线路信息缓存刷新
     */
    private void fileUpdateRefreshAllFeederCache(String feederId) {
        // 开启线程处理，刷新缓存的方法有点影响效率
        CompletableFuture.runAsync(() -> refreshCacheApiClient.refreshFeederCacheById(feederId), multiThreadExecuteService.getExecutor());
    }

    /**
     * 运行异常开关分合状态
     */
    private void dealDistLineSwitchStatus(List<StateEstimation.StateEstimationSwitchResult> list, Long objId) {
        // 开启线程运行异常开关分合状态保存
        CompletableFuture.runAsync(() -> {
            List<DistLineSwitchStatusPO> lineSwitchList = list.stream().map(e -> {
                DistLineSwitchStatusPO distLineSwitchStatus = new DistLineSwitchStatusPO();
                distLineSwitchStatus.setObjId(objId).setLineId(e.getFeederId()).setSwitchId(e.getPsrId())
                        .setClosedState(Optional.ofNullable(e.getSeoStatuss().get(0)).orElse(null))
                        .setIsAutoSwitch(e.getIsAuto());
                return distLineSwitchStatus;
            }).collect(Collectors.toList());
            // 先删后增开关状态信息
            distMappingFileMapper.deleteDistLineSwitchStatus(objId);
            distMappingFileMapper.insertDistLineSwitchStatus(lineSwitchList);
        }, multiThreadExecuteService.getExecutor());
    }

    /**
     * 获取状估接口的开关状态信息
     */
    private List<StateEstimation.StateEstimationSwitchResult> getStateEstimationResult(LocalDateTime currentTime, List<String> lineIds) {
        // 当前时间 前2个小时 组成起止时间, 后改称之前前两小时一个点
//        String endTime = currentTime.format(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN));
        String startTime = currentTime.minusHours(2).format(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN));

        // 状估接口参数
        StateEstimationRequest request = StateEstimationRequest.builder().psrIds(lineIds)
                .containerCode(Lists.newArrayList(SWITCH)).startTime(startTime).endTime(startTime).build();
        // 获取状估当前时刻点的开关状态数据
        StateEstimation stateEstimation = new StateEstimation();
        try {
            stateEstimation = stateEstimationService.queryByFeeder(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 获取状估结果返回的开关分合状态信息
        List<StateEstimation.StateEstimationSwitchResult> stateEstimationSwitchList = Optional.ofNullable(stateEstimation)
                .filter(e -> ObjectUtils.isNotEmpty(e.getPeriodSwitchSeResult()))
                .map(StateEstimation::getPeriodSwitchSeResult).orElse(Lists.newArrayList());

        return stateEstimationSwitchList;
    }

    /**
     * 处理SVG成图参数
     */
    private void dealDistDynamicSvgParameter(String objId, String objType, String switchId, String parameterInfo, DynamicSvgVO dynamicSvg) {
        // 根据返回结果来判断调用成功还是失败 0-成功，1-失败
        String callResult = Optional.ofNullable(dynamicSvg)
                .filter(e -> StringUtils.isNotEmpty(e.getSvgStr()))
                .map(e -> ZERO).orElse(ONE);
        distLineSwitchSectionMapper.saveDistDynamicSvgParameter(objId, objType, switchId, parameterInfo, callResult);
    }

}
