package com.aps.service.plan;

import com.aps.common.exception.BusinessException;
import com.aps.common.util.*;
import com.aps.common.util.redis.RedisUtils;
import com.aps.controller.gantt.FileUploadController;
import com.aps.entity.Algorithm.*;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.*;
import com.aps.entity.Gantt.ResourceGanttVO;
import com.aps.entity.Gantt.TaskVO;
import com.aps.entity.Schedule.GenVO;
import com.aps.entity.Schedule.MachineVO;
import com.aps.entity.Schedule.SceneChromsome;
import com.aps.entity.basic.*;
import com.aps.mapper.*;
import com.aps.service.Algorithm.*;
import com.aps.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
@Service
public class PlanResultService {
    private static final int PREVIEW_DATA_CACHE_SIZE = 32;
    private static final DateTimeFormatter API_TIMESTAMP_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    private final JsonFactory previewJsonFactory = new JsonFactory();
    private final Map<String, SceneVersionPreviewData> previewDataCache = Collections.synchronizedMap(
            new LinkedHashMap<String, SceneVersionPreviewData>(16, 0.75F, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry<String, SceneVersionPreviewData> eldest) {
                    return size() > PREVIEW_DATA_CACHE_SIZE;
                }
            }
    );
    // 注入FileUploadController
    @Autowired
    private FileUploadController fileUploadController;

    @Autowired
    private MesHolidayService _MesHolidayService;

    @Autowired
    private ProdEquipSpecialCalService _prodEquipSpecialCalService;

    @Autowired
    private MesShiftWorkSchedService _MesShiftWorkSchedService;


    @Autowired
    private ProdLaunchOrderService _prodLaunchOrderService;

    @Autowired
    private ProdProcessExecService _prodProcessExecService;

    @Autowired
    private ProdEquipmentService _prodEquipmentService;

    @Autowired
    private PlanResourceService _PlanResourceService;

    @Autowired
    private SceneService _sceneService;

    @Autowired
    private ProdOrderProcessService _prodOrderProcessService;

    @Autowired
    private  RoutingDiscreteParamService _routingDiscreteParamService;
    @Autowired
    private  DiscreteParameterMatrixService _discreteParameterMatrixService;

    @Autowired
    private RoutingDataService _routingDataService;

    @Autowired
    private ConfigService _configService;

    @Autowired
    private ConfigMapper configMapper;

    @Autowired
    private ApsTimeConfigMapper apsTimeConfigMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private ScheduleStrategyService scheduleStrategyService;

    @Autowired
    private OrderSortService orderSortService;

    @Autowired
    private LanuchService lanuchService;

    @Autowired
    private MaterialInfoMapper materialInfoMapper;

    @Autowired
    private MaterialPurchaseMapper materialPurchaseMapper;

    @Autowired
    private StockMapper stockMapper;



    @Autowired
    private SjzPfWhStockMapper sjzPfWhStockMapper;

    @Autowired
    private PurchaseReceiptMapper purchaseReceiptMapper;

    @Autowired
    private ErpPurchaseOrderMapper erpPurchaseOrderMapper;

    @Autowired
    private MaterialRequirementService materialRequirementService;
    @Autowired
    private EquipMaintainTaskService _equipMaintainTaskService;

    @Autowired
    private DispatchService dispatchService;

    @Autowired
    private ApsTimeConfigService apsTimeConfigService;

    @Autowired
    private LockedOrderProcessorService lockedOrderProcessorService;
    private  LocalDateTime baseTime = LocalDateTime.of(2025, 11, 1, 0, 0, 0);

    public List<ScheduleChromosome> execute() {
        return  null;
    }





    // 兼容旧调用：前端只传 sceneId 时，仍然会在内部根据场景创建人查找用户策略。
    /**
     * 只传场景ID时的排产入口。
     * 这里不强制要求前端传 userId / baseRuleId / userRuleId，
     * 后续会按场景创建人自动回退到可用的策略配置。
     */
    public Chromosome  execute2(String SceneId) {
       // return execute2(SceneId, 2361l, 241l, null);
        return execute2(SceneId, 2321l, 207l, null);

    }

    /**
     * 完整排产入口。
     * 传入的用户策略参数可选，缺省时会根据场景信息去找当前有效策略。
     */
    public Chromosome  execute2(String SceneId, Long userId, Long baseRuleId, String userRuleId) {
        try {

            ScheduleParams param = InitScheduleParams();
          //  param.setBaseTime(LocalDateTime.of(2026, 5, 20, 0, 0, 0));
            this.baseTime=param.getBaseTime();
            // 策略读取入口：优先使用前端传入的 userId；没传时用 sceneId 查场景创建人。
            Long effectiveUserId = scheduleStrategyService.resolveScheduleUserId(SceneId, userId);
            // 读取 /userStrategyRule/save 保存的用户策略；没有用户策略时会兜底全局策略。
            List<StrategyScheduling> strategySchedulings =
                    scheduleStrategyService.loadEffectiveForwardScheduling(effectiveUserId, baseRuleId, SceneId, userRuleId);

            // 1. 读取数据
            //  List<Machine> machines = loadData("machines.json", Machine.class);
            //  List<Product> products = loadData("products.json", Product.class);
            // List<Order> orders = loadData("orders.json", Order.class);

            List<ProdEquipment> ProdEquipments=  _prodEquipmentService.lambdaQuery()
                    .eq(ProdEquipment::getSceneId,SceneId)
                    .list();

            List<ProdLaunchOrder> ProdLaunchOrders=  _prodLaunchOrderService.lambdaQuery()
                    .eq(ProdLaunchOrder::getSceneId,SceneId)
                    .list();
            GlobalParam globalParam = buildInitialGlobalParam(SceneId, effectiveUserId, baseRuleId, userRuleId);

            // 3. 创建调度服务
            MachineSchedulerService machineScheduler = new MachineSchedulerService(
                    param.getBaseTime());
            List<Machine> machines= InitCalendarToAllMachines(SceneId, ProdEquipments,machineScheduler,globalParam.isIsUseCalendar());
            // 3. 构建订单-工序数据



            List<Order> orders=InitOrder(ProdLaunchOrders, strategySchedulings);

            List<Material> Materials= InitMaterial();

            Map<Integer,Object> list= InitEntrys(SceneId,ProdEquipments,orders);
            List<Entry> entrys=(List<Entry>)list.get(1);


            List<GroupResult> entryRel=(List<GroupResult>)list.get(2);

            Map<Long,Double> machineIds=(Map<Long,Double>)list.get(3);

            Map<Integer,Object> reslte=materialRequirementService.preloadRoutingCache(SceneId,param.getBaseTime(), orders,Materials,entrys,globalParam.isIsCheckSf());
            List<Long> equipIDs=(List<Long>) reslte.get(1);
            List<Material> Materials1=(List<Material>) reslte.get(2);

            List<Long> machineIds1=machineIds.keySet().stream().collect(Collectors.toList());
            if(equipIDs!=null&&equipIDs.size()>0)
            {
                machineIds1.addAll(equipIDs);
            }


            machines= machines.stream().filter(t->machineIds1.contains(t.getId())).collect(Collectors.toList());

            for (Machine machine : machines){
                Long machineId=machine.getId();

                if(machineIds.get(machineId)!=null&&machineIds.get(machineId)>3600*24*200) {

                    int day = (int) (machineIds.get(machineId) / 3600 / 24)+100;
                   // day=Math.min(day,400);
                    List<TimeSegment> segments = machineScheduler.generateTimeSegment(machine, null, day);
                    machineScheduler.addSegmentsWithDeduplication(machine, segments);
                }
            }

            // 按照优先级排序
            entrys.sort(
                    Comparator.comparing(Entry::getPriority)
            );


            List<String> materialIds = Materials1.stream()
                    .map(Material::getId)
                    .distinct()
                    .collect(Collectors.toList());
            ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
            // 4.5 在排产前标记锁定期工单占用的设备时间段
            lockedOrderProcessorService.markLockedOrdersOccupiedTime(machines, timeConfig.getBaseTime());

            TreeMap<String, Material> materialmap=   materialRequirementService.GetMaterialListToMap(Materials1);


            // 5. 执行调度算法
            HybridAlgorithm scheduler =new HybridAlgorithm(globalParam,machines,orders,materialmap,materialIds,machineScheduler,entryRel,materialRequirementService,_sceneService,SceneId); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
            param.initAdaptiveParams(entrys.size());
          //  double[] customWeights = new double[] { 0.4, 0.1, 0.1, 0.1, 0.3 }; // 延迟时间权重提升到0.5
            //完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
          //  scheduler.Init();
            Chromosome chromosome =scheduler.Run(param,entrys);

            KpiCalculator kpiCalculator=new KpiCalculator(chromosome);
            kpiCalculator.calculatekpi();

          // int NotInAllOperations= chromosome.getResultsNotInAllOperations().size();


            // 添加锁定期工单到调度结果中
            // 这里会从 Dispatch 表加载锁定期工单，并添加到 chromosome.result 中
            lockedOrderProcessorService.addLockedOrdersToResult(chromosome);

            saveGlobalParamSnapshot(chromosome, globalParam);
            boolean saved = _sceneService.saveChromosomeToFile(chromosome, SceneId);
            if (!saved) {
                throw new BusinessException("排产计算结果保存失败，请稍后重试或联系管理员");
            }
            WriteScheduleSummary(chromosome);

            return chromosome;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessException("排产计算失败，请检查场景数据后重试", e);
        }
    }



//    /**
//     * 添加锁定期工单到调度结果中
//     * 从上一次排产结果中获取冻结期内的工单，保持时间、数量、设备、Entry等信息不变
//     * @param chromosome 染色体对象
//     */
//    private void addLockedOrdersToResult(Chromosome chromosome) {
//        try {
//            // 1. 获取时间配置
//            ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
//            if (timeConfig == null || timeConfig.getBaseTime() == null) {
//                log.warn("未找到ApsTimeConfig配置或baseTime为空，无法添加锁定期工单");
//                return;
//            }
//
//            LocalDateTime baseTime = timeConfig.getBaseTime();
//            long freezeSeconds = timeConfig.getFreezeDate() != null ? timeConfig.getFreezeDate().longValue() : 0;
//
//            // 如果freezeSeconds为0，则不添加锁定期工单
//            if (freezeSeconds <= 0) {
//                log.debug("冻结期秒数为{}，跳过添加锁定期工单", freezeSeconds);
//                return;
//            }
//
//            // 锁定期计算：baseTime 到 baseTime + freezeSeconds
//            LocalDateTime lockStartTime = baseTime;
//            LocalDateTime lockEndTime = baseTime.plusSeconds(freezeSeconds);
//
//            log.info("锁定期范围: {} 到 {} (冻结期: {}秒)", lockStartTime, lockEndTime, freezeSeconds);
//
//            // 2. 尝试从已下发的排产结果中获取锁定期工单
//            List<GAScheduleResult> lockedResults = new ArrayList<>();
//            Map<String, Entry> lockedEntries = new HashMap<>();
//            Set<Long> lockedMachineIds = new HashSet<>();
//
//            try {
//                // 从Dispatch表查询锁定期内的工单，获取它们的sceneId
//                List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
//                        .ge(Dispatch::getBeginTime, lockStartTime)
//                        .le(Dispatch::getBeginTime, lockEndTime)
//                        .eq(Dispatch::getIsDeleted, 0L)
//                        .orderBy(true, true, Dispatch::getMesCode, Dispatch::getTaskSeq)
//                        .list();
//
//                if (frozenDispatches.isEmpty()) {
//                    log.info("冻结期内没有工单需要添加");
//                    return;
//                }
//
//                log.info("查询到冻结期内的工序数: {}", frozenDispatches.size());
//
//                // 获取这些工单的所有不同sceneId（可能来自多个已下发的场景）
//                Set<String> dispatchSceneIds = frozenDispatches.stream()
//                        .map(Dispatch::getSceneId)
//                        .filter(id -> id != null && !id.isEmpty())
//                        .collect(Collectors.toSet());
//
//                if (!dispatchSceneIds.isEmpty()) {
//                    log.info("锁定期工单来自 {} 个已下发场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
//
//                    // 遍历每个场景，尝试加载排产结果
//                    for (String dispatchSceneId : dispatchSceneIds) {
//                        try {
//                            log.info("处理场景: {}", dispatchSceneId);
//
//                            // 尝试加载已下发场景的排产结果
//                            SceneChromsome dispatchSceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + dispatchSceneId);
//                            if (dispatchSceneChromsome != null) {
//                                int dispatchVersion = dispatchSceneChromsome.getVersion();
//                                File dispatchFile = new File("result", "chromosome_result_" + dispatchSceneId + "_" + dispatchVersion + "_.json");
//
//                                if (dispatchFile.exists()) {
//                                    ObjectMapper objectMapper = new ObjectMapper();
//                                    objectMapper.registerModule(new JavaTimeModule());
//                                    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//                                    objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//
//                                    Chromosome dispatchChromosome = objectMapper.readValue(dispatchFile, Chromosome.class);
//
//                                    if (dispatchChromosome.getResult() != null) {
//                                        // 获取已下发场景的baseTime
//                                        LocalDateTime dispatchBaseTime = dispatchChromosome.getBaseTime();
//                                        if (dispatchBaseTime == null) {
//                                            log.warn("场景 {} 的baseTime为空，无法计算时间偏移", dispatchSceneId);
//                                            continue;
//                                        }
//
//                                        log.info("场景 {} - 已下发场景baseTime: {}, 新场景baseTime: {}", dispatchSceneId, dispatchBaseTime, baseTime);
//
//                                        // 筛选属于当前场景的工单
//                                        List<Dispatch> currentSceneDispatches = frozenDispatches.stream()
//                                                .filter(d -> dispatchSceneId.equals(d.getSceneId()))
//                                                .collect(Collectors.toList());
//
//                                        // 第一步：找出所有在锁定期内有工序的订单ID
//                                        Set<String> lockedOrderIds = new HashSet<>();
//                                        log.info("场景 {} 开始分析工序时间，锁定期范围: {} 到 {}", dispatchSceneId, lockStartTime, lockEndTime);
//
//                                        for (GAScheduleResult prevResult : dispatchChromosome.getResult()) {
//                                            LocalDateTime prevStartTime = dispatchBaseTime.plusSeconds(prevResult.getStartTime());
//
//                                            log.debug("分析工序: ExecId={}, OrderId={}, 原始StartTime={}秒, 绝对开始时间={}",
//                                                prevResult.getExecId(), prevResult.getOrderId(), prevResult.getStartTime(), prevStartTime);
//
//                                            // 如果该工序的开始时间在锁定期内，记录其订单ID
//                                            if (!prevStartTime.isBefore(lockStartTime) && !prevStartTime.isAfter(lockEndTime)) {
//                                                log.info("工序在锁定期内: ExecId={}, OrderId={}, 开始时间={}",
//                                                    prevResult.getExecId(), prevResult.getOrderId(), prevStartTime);
//
//                                                // 检查是否有对应的Dispatch记录（通过订单号和时间范围匹配，而不是ExecId）
//                                                boolean hasValidDispatchRecord = currentSceneDispatches.stream()
//                                                        .anyMatch(d -> d.getMesCode() != null &&
//                                                                      d.getMesCode().equals(prevResult.getOrderId()) &&
//                                                                      d.getBeginTime() != null &&
//                                                                      !d.getBeginTime().isBefore(lockStartTime) &&
//                                                                      !d.getBeginTime().isAfter(lockEndTime));
//
//                                                if (hasValidDispatchRecord && prevResult.getOrderId() != null) {
//                                                    lockedOrderIds.add(prevResult.getOrderId());
//                                                    log.info("订单 {} 被标记为锁定期订单（通过订单号匹配）", prevResult.getOrderId());
//                                                } else {
//                                                    log.warn("工序 {} 在锁定期内但没有有效的Dispatch记录（订单号: {}）",
//                                                        prevResult.getExecId(), prevResult.getOrderId());
//                                                }
//                                            } else {
//                                                log.debug("工序不在锁定期内: ExecId={}, 开始时间={}, 锁定期: {} 到 {}",
//                                                    prevResult.getExecId(), prevStartTime, lockStartTime, lockEndTime);
//                                            }
//                                        }
//
//                                        log.info("场景 {} 中发现 {} 个订单在锁定期内有工序: {}", dispatchSceneId, lockedOrderIds.size(), lockedOrderIds);
//
//                                        // 第二步：获取这些订单的所有工序（包括锁定期外的工序）
//                                        for (GAScheduleResult prevResult : dispatchChromosome.getResult()) {
//                                            // 如果该工序属于锁定期订单，则保留（不管工序本身是否在锁定期内）
//                                            if (lockedOrderIds.contains(prevResult.getOrderId())) {
//                                                // 检查是否有对应的Dispatch记录（通过订单号匹配）
//                                                boolean hasDispatchRecord = currentSceneDispatches.stream()
//                                                        .anyMatch(d -> d.getMesCode() != null &&
//                                                                      d.getMesCode().equals(prevResult.getOrderId()));
//
//                                                if (hasDispatchRecord) {
//                                                    // 将已下发场景的相对时间转换为绝对时间
//                                                    LocalDateTime prevStartTime = dispatchBaseTime.plusSeconds(prevResult.getStartTime());
//                                                    LocalDateTime prevEndTime = dispatchBaseTime.plusSeconds(prevResult.getEndTime());
//
//                                                    // 深拷贝工单信息
//                                                    GAScheduleResult lockedResult = copyGAScheduleResult(prevResult);
//                                                    lockedResult.setIsLocked(true); // 标记为锁定
//
//                                                    // 重新计算相对于新baseTime的时间
//                                                    int newStartTime = (int) ChronoUnit.SECONDS.between(baseTime, prevStartTime);
//                                                    int newEndTime = (int) ChronoUnit.SECONDS.between(baseTime, prevEndTime);
//                                                    lockedResult.setStartTime(newStartTime);
//                                                    lockedResult.setEndTime(newEndTime);
//
//                                                    lockedResults.add(lockedResult);
//                                                    lockedMachineIds.add(prevResult.getMachineId());
//
//                                                    boolean isInLockPeriod = !prevStartTime.isBefore(lockStartTime) && !prevStartTime.isAfter(lockEndTime);
//                                                    log.info("从场景 {} 获取订单 {} 的工序: ExecId={}, OrderCode={}, MachineId={}, 原始时间=[{} 到 {}], 新相对时间=[{} 到 {}]秒, 是否在锁定期内={}",
//                                                        dispatchSceneId, prevResult.getOrderId(), lockedResult.getExecId(), lockedResult.getOrderCode(), lockedResult.getMachineId(),
//                                                        prevStartTime, prevEndTime, newStartTime, newEndTime, isInLockPeriod);
//                                                } else {
//                                                    log.warn("订单 {} 的工序 {} 没有对应的Dispatch记录", prevResult.getOrderId(), prevResult.getExecId());
//                                                }
//                                            }
//                                        }
//
//                                        // 从已下发场景的排产结果中获取对应的Entry信息
//                                        if (dispatchChromosome.getAllOperations() != null) {
//                                            log.info("场景 {} 中有 {} 个Entry，开始匹配锁定期工单的Entry信息", dispatchSceneId, dispatchChromosome.getAllOperations().size());
//
//                                            for (GAScheduleResult lockedResult : lockedResults) {
//                                                log.debug("处理锁定期工单: ExecId={}, OperationId={}", lockedResult.getExecId(), lockedResult.getOperationId());
//
//                                                if (lockedResult.getOperationId() > 0) {
//                                                    Entry prevEntry = dispatchChromosome.getAllOperations().stream()
//                                                            .filter(e -> e.getId() == lockedResult.getOperationId())
//                                                            .findFirst()
//                                                            .orElse(null);
//
//                                                    if (prevEntry != null) {
//                                                        lockedEntries.put(lockedResult.getExecId(), prevEntry);
//                                                        log.debug("找到匹配的Entry: ExecId={}, EntryId={}, RoutingDetailId={}",
//                                                            lockedResult.getExecId(), prevEntry.getId(), prevEntry.getRoutingDetailId());
//                                                    } else {
//                                                        log.warn("未找到OperationId={}对应的Entry", lockedResult.getOperationId());
//                                                    }
//                                                } else {
//                                                    log.warn("锁定期工单的OperationId为0，无法匹配Entry: ExecId={}", lockedResult.getExecId());
//
//                                                    // 尝试通过ExecId匹配Entry
//                                                    Entry prevEntry = dispatchChromosome.getAllOperations().stream()
//                                                            .filter(e -> e.getExecId().equals(lockedResult.getExecId()))
//                                                            .findFirst()
//                                                            .orElse(null);
//
//                                                    if (prevEntry != null) {
//                                                        lockedEntries.put(lockedResult.getExecId(), prevEntry);
//                                                        // 同时修正OperationId
//                                                        lockedResult.setOperationId(prevEntry.getId());
//                                                        log.info("通过ExecId匹配到Entry并修正OperationId: ExecId={}, EntryId={}, RoutingDetailId={}",
//                                                            lockedResult.getExecId(), prevEntry.getId(), prevEntry.getRoutingDetailId());
//                                                    } else {
//                                                        log.warn("通过ExecId也未找到对应的Entry: ExecId={}", lockedResult.getExecId());
//                                                    }
//                                                }
//                                            }
//
//                                            log.info("场景 {} 成功匹配 {} 个Entry信息", dispatchSceneId, lockedEntries.size());
//                                        }
//
//                                    } else {
//                                        log.warn("场景 {} 的排产结果为空", dispatchSceneId);
//                                    }
//                                } else {
//                                    log.warn("场景 {} 的排产结果文件不存在: {}", dispatchSceneId, dispatchFile.getAbsolutePath());
//                                }
//                            } else {
//                                log.warn("未找到场景 {} 的版本信息", dispatchSceneId);
//                            }
//                        } catch (Exception ex) {
//                            log.error("处理场景 {} 的排产结果失败: {}", dispatchSceneId, ex.getMessage(), ex);
//                        }
//                    }
//
//                    log.info("从 {} 个已下发场景排产结果中获取到 {} 个锁定期工单", dispatchSceneIds.size(), lockedResults.size());
//                } else {
//                    log.warn("Dispatch表中的工单没有sceneId信息");
//                }
//            } catch (Exception ex) {
//                log.error("从已下发场景排产结果获取锁定期工单失败: {}", ex.getMessage(), ex);
//            }
//
//            // 3. 如果无法从上次排产获取，则从Dispatch表查询
//            if (lockedResults.isEmpty()) {
//                log.info("从Dispatch表查询锁定期工单");
//                List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
//                        .ge(Dispatch::getBeginTime, lockStartTime)
//                        .le(Dispatch::getBeginTime, lockEndTime)
//                        .eq(Dispatch::getIsDeleted, 0L)
//                        .orderBy(true, true, Dispatch::getMesCode, Dispatch::getTaskSeq)
//                        .list();
//
//                if (frozenDispatches.isEmpty()) {
//                    log.info("冻结期内没有工单需要添加");
//                    return;
//                }
//
//                log.info("查询到冻结期内的工序数: {}", frozenDispatches.size());
//
//                for (Dispatch dispatch : frozenDispatches) {
//                    GAScheduleResult result = new GAScheduleResult();
//
//                    log.info("处理Dispatch记录: id={}, executeId={}, mesCode={}, equipId={}, beginTime={}, endTime={}",
//                        dispatch.getId(), dispatch.getExecuteId(), dispatch.getMesCode(),
//                        dispatch.getEquipId(), dispatch.getBeginTime(), dispatch.getEndTime());
//
//                    // 设置基本信息
//                    result.setOperationId(dispatch.getExecuteId() != null ? dispatch.getExecuteId().intValue() : 0);
//                    result.setExecId(dispatch.getExecuteId() != null ? dispatch.getExecuteId().toString() : "");
//                    result.setOrderId(dispatch.getMesCode() != null ? dispatch.getMesCode() : "");
//                    result.setOrderCode(dispatch.getMesCode());
//                    result.setMachineId(dispatch.getEquipId() != null ? dispatch.getEquipId() : 0L);
//                    result.setQuantity(dispatch.getQuantity() != null ? dispatch.getQuantity() : 0.0);
//
//                    // 设置产品信息（从Dispatch表中可能没有，使用默认值）
//                    result.setProductId("");
//                    result.setProductName("");
//                    result.setProductCode("");
//
//                    log.info("从Dispatch创建锁定期工单: executeId={}, OperationId={}, mesCode={}",
//                        dispatch.getExecuteId(), result.getOperationId(), dispatch.getMesCode());
//
//                    // 计算相对时间（相对于baseTime的秒数）
//                    // 注意：锁定期工单的时间通常在baseTime之前，所以会是负数
//                    if (dispatch.getBeginTime() != null && dispatch.getEndTime() != null) {
//                        // 使用Dispatch表中的绝对时间，计算相对于baseTime的偏移（负数表示在baseTime之前）
//                        int startTime = (int) ChronoUnit.SECONDS.between(baseTime, dispatch.getBeginTime());
//                        int endTime = (int) ChronoUnit.SECONDS.between(baseTime, dispatch.getEndTime());
//
//                        log.info("锁定期工单时间计算: ExecId={}, Dispatch时间=[{} 到 {}], baseTime={}, 相对时间=[{} 到 {}]秒",
//                            dispatch.getExecuteId(), dispatch.getBeginTime(), dispatch.getEndTime(),
//                            baseTime, startTime, endTime);
//
//                        result.setStartTime(startTime);
//                        result.setEndTime(endTime);
//                        result.setProcessingTime((double) (endTime - startTime) / 60.0); // 转换为分钟
//                    }
//
//                    // 设置其他信息
//                    result.setIsLocked(true); // 标记为锁定
//                    result.setTeardownTime(0);
//                    result.setChangeOverTime(0);
//                    result.setPreTime(0);
//                    result.setSeq(dispatch.getTaskSeq() != null ? dispatch.getTaskSeq().intValue() : 0);
//                    result.setBomTime(0);
//                    result.setDesignatedStartTime(-1);
//                    result.setLockStartTime(0);
//                    result.setForcedMachineId(-1L);
//
//                    // 创建GeneDetails
//                    List<ScheduleResultDetail> geneDetails = new ArrayList<>();
//                    ScheduleResultDetail detail = new ScheduleResultDetail();
//                    detail.setStartTime(result.getStartTime());
//                    detail.setEndTime(result.getEndTime());
//                    detail.setQuantity(dispatch.getQuantity() != null ? dispatch.getQuantity() : 0.0);
//                    geneDetails.add(detail);
//                    result.setGeneDetails(geneDetails);
//
//                    lockedResults.add(result);
//                    lockedMachineIds.add(result.getMachineId());
//
//                    log.debug("添加锁定期工单: ExecId={}, OrderCode={}, MachineId={}, StartTime={}, EndTime={}",
//                        result.getExecId(), result.getOrderCode(), result.getMachineId(), result.getStartTime(), result.getEndTime());
//                }
//            }
//
//            // 4. 添加到chromosome的result中
//            if (chromosome.getResult() == null) {
//                log.warn("chromosome.getResult()为null，创建新的CopyOnWriteArrayList");
//                chromosome.setResult(new CopyOnWriteArrayList<>());
//            }
//
//            int beforeSize = chromosome.getResult().size();
//            chromosome.getResult().addAll(lockedResults);
//            int afterSize = chromosome.getResult().size();
//
//            log.info("成功添加 {} 个锁定期工单到调度结果中，result大小从{}变为{}", lockedResults.size(), beforeSize, afterSize);
//
//            // 5. 从已下发场景复制锁定期订单的Order对象
//            if (!lockedResults.isEmpty()) {
//                if (chromosome.getOrders() == null) {
//                    chromosome.setOrders(new CopyOnWriteArrayList<>());
//                }
//
//                int beforeOrderSize = chromosome.getOrders().size();
//
//                // 收集锁定期工单的订单ID
//                Set<String> lockedOrderIds = lockedResults.stream()
//                        .map(GAScheduleResult::getOrderId)
//                        .filter(Objects::nonNull)
//                        .collect(Collectors.toSet());
//
//                log.info("需要复制的锁定期订单ID: {}", lockedOrderIds);
//
//                // 从已下发场景中复制对应的Order对象
//                try {
//                    // 获取已下发场景的sceneId
//                    List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
//                            .ge(Dispatch::getBeginTime, lockStartTime)
//                            .le(Dispatch::getBeginTime, lockEndTime)
//                            .eq(Dispatch::getIsDeleted, 0L)
//                            .list();
//
//                    log.info("查询到 {} 个锁定期Dispatch记录", frozenDispatches.size());
//
//                    Set<String> dispatchSceneIds = frozenDispatches.stream()
//                            .map(Dispatch::getSceneId)
//                            .filter(id -> id != null && !id.isEmpty())
//                            .collect(Collectors.toSet());
//
//                    log.info("锁定期Dispatch记录来自 {} 个场景: {}", dispatchSceneIds.size(), dispatchSceneIds);
//
//                    // 遍历每个已下发场景，复制锁定期订单
//                    for (String dispatchSceneId : dispatchSceneIds) {
//                        try {
//                            log.info("开始从场景 {} 加载Chromosome", dispatchSceneId);
//                            Chromosome dispatchChromosome = _sceneService.loadChromosomeFromFile(dispatchSceneId);
//
//                            if (dispatchChromosome != null) {
//                                log.info("场景 {} 加载成功，Orders数量: {}", dispatchSceneId,
//                                    dispatchChromosome.getOrders() != null ? dispatchChromosome.getOrders().size() : 0);
//
//                                if (dispatchChromosome.getOrders() != null) {
//                                    // 筛选出锁定期订单
//                                    List<Order> lockedOrders = dispatchChromosome.getOrders().stream()
//                                            .filter(order -> {
//                                                boolean matches = lockedOrderIds.contains(order.getOrderId());
//                                                log.debug("订单 {} 是否匹配锁定期: {}", order.getOrderId(), matches);
//                                                return matches;
//                                            })
//                                            .collect(Collectors.toList());
//
//                                    log.info("场景 {} 中找到 {} 个匹配的锁定期订单", dispatchSceneId, lockedOrders.size());
//
//                                    // 复制到当前场景，避免重复添加
//                                    for (Order lockedOrder : lockedOrders) {
//                                        boolean exists = chromosome.getOrders().stream()
//                                                .anyMatch(order -> lockedOrder.getOrderId().equals(order.getOrderId()));
//
//                                        if (!exists) {
//                                            // 直接添加原Order对象（已包含完整信息）
//                                            chromosome.getOrders().add(lockedOrder);
//
//                                            log.info("从场景 {} 复制锁定期订单: OrderId={}, OrderCode={}",
//                                                dispatchSceneId, lockedOrder.getOrderId(), lockedOrder.getOrderCode());
//                                        } else {
//                                            log.warn("订单 {} 已存在，跳过复制", lockedOrder.getOrderId());
//                                        }
//                                    }
//                                } else {
//                                    log.warn("场景 {} 的Orders为null", dispatchSceneId);
//                                }
//                            } else {
//                                log.warn("场景 {} 加载失败，Chromosome为null", dispatchSceneId);
//                            }
//                        } catch (Exception ex) {
//                            log.error("从场景 {} 复制锁定期订单失败: {}", dispatchSceneId, ex.getMessage(), ex);
//                        }
//                    }
//                } catch (Exception e) {
//                    log.error("复制锁定期订单失败: {}", e.getMessage(), e);
//                }
//
//                int afterOrderSize = chromosome.getOrders().size();
//                log.info("成功复制锁定期订单到Orders列表，大小从{}变为{}", beforeOrderSize, afterOrderSize);
//            }
//
//            // 5. 添加锁定期Entry到allOperations中
//            if (!lockedEntries.isEmpty() && chromosome.getAllOperations() != null) {
//                int beforeEntrySize = chromosome.getAllOperations().size();
//                chromosome.getAllOperations().addAll(lockedEntries.values());
//                log.info("成功添加 {} 个锁定期Entry到allOperations中，大小从{}变为{}",
//                    lockedEntries.size(), beforeEntrySize, chromosome.getAllOperations().size());
//            }
//
//            // 5. 确保锁定期工单使用的设备在initMachines中
//            // 如果设备在本次排产中没有使用，则从已下发场景中获取设备信息
//            if (chromosome.getInitMachines() != null && !lockedMachineIds.isEmpty()) {
//                Set<Long> existingMachineIds = chromosome.getInitMachines().stream()
//                        .map(Machine::getId)
//                        .collect(Collectors.toSet());
//
//                // 筛选出不在本次排产中的设备
//                Set<Long> missingMachineIds = lockedMachineIds.stream()
//                        .filter(id -> id != null && id > 0 && !existingMachineIds.contains(id))
//                        .collect(Collectors.toSet());
//
//                if (!missingMachineIds.isEmpty()) {
//                    log.info("锁定期工单使用的设备不在本次排产中，需要从已下发场景获取设备信息: {}", missingMachineIds);
//
//                    // 尝试从已下发场景的排产结果中获取这些设备的信息
//                    try {
//                        // 从Dispatch表查询锁定期内的工单，获取它们的所有sceneId
//                        List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
//                                .ge(Dispatch::getBeginTime, lockStartTime)
//                                .le(Dispatch::getBeginTime, lockEndTime)
//                                .eq(Dispatch::getIsDeleted, 0L)
//                                .list();
//
//                        // 获取所有已下发场景的sceneId
//                        Set<String> dispatchSceneIds = frozenDispatches.stream()
//                                .map(Dispatch::getSceneId)
//                                .filter(id -> id != null && !id.isEmpty())
//                                .collect(Collectors.toSet());
//
//                        boolean foundMachines = false;
//
//                        // 遍历每个场景查找设备信息
//                        for (String dispatchSceneId : dispatchSceneIds) {
//                            if (foundMachines) break; // 如果已经找到所有设备，跳出循环
//
//                            try {
//                                log.info("从场景 {} 获取设备信息", dispatchSceneId);
//
//                                // 加载已下发场景的排产结果
//                                SceneChromsome dispatchSceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + dispatchSceneId);
//                                if (dispatchSceneChromsome != null) {
//                                    int dispatchVersion = dispatchSceneChromsome.getVersion();
//                                    File dispatchFile = new File("result", "chromosome_result_" + dispatchSceneId + "_" + dispatchVersion + "_.json");
//
//                                    if (dispatchFile.exists()) {
//                                        ObjectMapper objectMapper = new ObjectMapper();
//                                        objectMapper.registerModule(new JavaTimeModule());
//                                        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//                                        objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//
//                                        Chromosome dispatchChromosome = objectMapper.readValue(dispatchFile, Chromosome.class);
//
//                                        if (dispatchChromosome.getInitMachines() != null) {
//                                            // 从已下发场景的排产结果中查找这些设备
//                                            List<Machine> dispatchMachines = dispatchChromosome.getInitMachines().stream()
//                                                    .filter(m -> missingMachineIds.contains(m.getId()))
//                                                    .collect(Collectors.toList());
//
//                                            if (!dispatchMachines.isEmpty()) {
//                                                log.info("从场景 {} 的排产结果中找到 {} 个锁定期设备", dispatchSceneId, dispatchMachines.size());
//                                                chromosome.getInitMachines().addAll(dispatchMachines);
//
//                                                // 从缺失列表中移除已找到的设备
//                                                Set<Long> foundMachineIds = dispatchMachines.stream()
//                                                        .map(Machine::getId)
//                                                        .collect(Collectors.toSet());
//                                                missingMachineIds.removeAll(foundMachineIds);
//
//                                                // 如果所有设备都找到了，标记为完成
//                                                if (missingMachineIds.isEmpty()) {
//                                                    foundMachines = true;
//                                                }
//                                            }
//                                        }
//                                    } else {
//                                        log.warn("场景 {} 的排产结果文件不存在: {}", dispatchSceneId, dispatchFile.getAbsolutePath());
//                                    }
//                                } else {
//                                    log.warn("未找到场景 {} 的版本信息", dispatchSceneId);
//                                }
//                            } catch (Exception ex) {
//                                log.error("从场景 {} 获取设备信息失败: {}", dispatchSceneId, ex.getMessage(), ex);
//                            }
//                        }
//
//                        // 如果还有设备没找到，创建默认设备信息
//                        if (!missingMachineIds.isEmpty()) {
//                            log.warn("在所有已下发场景中都没有找到锁定期设备，将创建默认设备信息: {}", missingMachineIds);
//                            createDefaultMachines(chromosome, missingMachineIds);
//                        }
//                    } catch (Exception ex) {
//                        log.error("从已下发场景排产结果获取设备信息失败: {}", ex.getMessage(), ex);
//                        createDefaultMachines(chromosome, missingMachineIds);
//                    }
//                }
//            }
//
//        } catch (Exception e) {
//            log.error("添加锁定期工单时发生错误: {}", e.getMessage(), e);
//        }
//    }
//
//    /**
//     * 为锁定期工单创建默认设备信息
//     * @param chromosome 染色体对象
//     * @param machineIds 需要创建的设备ID集合
//     */
//    private void createDefaultMachines(Chromosome chromosome, Set<Long> machineIds) {
//        try {
//            // 查询这些设备的信息
//            List<PlanResource> planResources = _PlanResourceService.lambdaQuery()
//                    .eq(PlanResource::getIsdeleted, 0)
//                    .in(PlanResource::getId, machineIds.stream()
//                            .map(Long::intValue)
//                            .collect(Collectors.toList()))
//                    .list();
//
//            // 查询班次信息
//            List<MesShiftWorkSched> allShiftWorkScheds = _MesShiftWorkSchedService.lambdaQuery()
//                    .eq(MesShiftWorkSched::getIsdeleted, 0)
//                    .list();
//
//            // 创建Machine对象并添加到initMachines
//            for (Long machineId : machineIds) {
//                Machine machine = new Machine();
//                machine.setId(machineId);
//
//                PlanResource planResource = planResources.stream()
//                        .filter(pr -> pr.getId() == machineId.intValue())
//                        .findFirst()
//                        .orElse(null);
//
//                if (planResource != null) {
//                    machine.setCode(planResource.getReferenceCode());
//                    machine.setName(planResource.getTitle());
//                    machine.setDepartment(planResource.getDepartTitle());
//
//                    log.info("为设备 {} 查询班次信息，workSchedId: {}", machineId, planResource.getWorkSchedId());
//
//                    // 查询设备的真实班次信息
//                    List<MesShiftWorkSched> shiftWorkScheds = allShiftWorkScheds.stream()
//                            .filter(t -> (long) t.getWeekWorkSchedId() == planResource.getWorkSchedId())
//                            .collect(Collectors.toList());
//
//                    log.info("设备 {} 找到 {} 个班次记录", machineId, shiftWorkScheds.size());
//
//                    if (!shiftWorkScheds.isEmpty()) {
//                        // 使用真实的班次信息
//                        List<Shift> shifts = mergeShiftData(shiftWorkScheds);
//                        for (Shift shift : shifts) {
//                            shift.setMachineId(machineId);
//                            shift.setSpecial(false);
//                            shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
//                            shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
//                        }
//                        machine.setShifts(shifts);
//                        log.info("为设备 {} 设置真实班次信息，共 {} 个班次", machineId, shifts.size());
//                    } else {
//                        // 如果没有找到班次信息，使用默认24小时班次
//                        machine.setShifts(createDefault24HourShift(machineId));
//                        log.warn("设备 {} 没有找到班次信息，使用默认24小时班次", machineId);
//                    }
//                } else {
//                    machine.setCode("LOCKED-" + machineId);
//                    machine.setName("锁定期设备-" + machineId);
//                    // 使用默认24小时班次
//                    machine.setShifts(createDefault24HourShift(machineId));
//                    log.warn("设备 {} 没有找到PlanResource信息，使用默认24小时班次", machineId);
//                }
//
//                chromosome.getInitMachines().add(machine);
//            }
//
//            log.info("成功创建 {} 个默认锁定期设备", machineIds.size());
//        } catch (Exception e) {
//            log.error("创建默认设备信息失败: {}", e.getMessage(), e);
//        }
//    }
//
//    /**
//     * 创建默认的24小时班次
//     * @param machineId 设备ID
//     * @return 24小时班次列表
//     */
//    private List<Shift> createDefault24HourShift(Long machineId) {
//        List<Shift> shifts = new ArrayList<>();
//        Shift shift = new Shift();
//        shift.setMachineId(machineId);
//        shift.setStartTime(LocalTime.of(0, 0, 0));
//        shift.setEndTime(LocalTime.of(23, 59, 59));
//        HashSet<Integer> days = new HashSet<>();
//        for (int i = 0; i <= 6; i++) {
//            days.add(i);
//        }
//        shift.setDays(days);
//        shift.setSpecial(false);
//        shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
//        shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
//        shifts.add(shift);
//        return shifts;
//    }
//
//    /**
//     * 深拷贝 GAScheduleResult 对象
//     *
//     * @param source 源对象
//     * @return 拷贝后的新对象
//     */
//    private GAScheduleResult copyGAScheduleResult(GAScheduleResult source) {
//        if (source == null) {
//            return null;
//        }
//
//        GAScheduleResult copy = new GAScheduleResult();
//
//        // 拷贝基本字段
//        copy.setGroupId(source.getGroupId());
//        copy.setOperationId(source.getOperationId());
//        copy.setExecId(source.getExecId());
//        copy.setOrderId(source.getOrderId());
//        copy.setOrderCode(source.getOrderCode());
//        copy.setProductId(source.getProductId());
//        copy.setProductName(source.getProductName());
//        copy.setProductCode(source.getProductCode());
//        copy.setMachineId(source.getMachineId());
//        copy.setStartTime(source.getStartTime());
//        copy.setEndTime(source.getEndTime());
//        copy.setTeardownTime(source.getTeardownTime());
//        copy.setQuantity(source.getQuantity());
//        copy.setDesignatedStartTime(source.getDesignatedStartTime());
//        copy.setLockStartTime(source.getLockStartTime());
//        copy.setForcedMachineId(source.getForcedMachineId());
//        copy.setIsLocked(source.isIsLocked());
//        copy.setOneTime(source.getOneTime());
//        copy.setProcessingTime(source.getProcessingTime());
//        copy.setChangeOverTime(source.getChangeOverTime());
//        copy.setPreTime(source.getPreTime());
//        copy.setSeq(source.getSeq());
//        copy.setBomTime(source.getBomTime());
//
//        // 深拷贝 GeneDetails 列表
//        if (source.getGeneDetails() != null) {
//            List<ScheduleResultDetail> detailsCopy = new ArrayList<>();
//            for (ScheduleResultDetail detail : source.getGeneDetails()) {
//                ScheduleResultDetail detailCopy = new ScheduleResultDetail();
//                detailCopy.setKey(detail.getKey());
//                detailCopy.setStartTime(detail.getStartTime());
//                detailCopy.setEndTime(detail.getEndTime());
//                detailCopy.setOneTime(detail.getOneTime());
//                detailCopy.setQuantity(detail.getQuantity());
//
//                // 深拷贝 usedSegment
//                if (detail.getUsedSegment() != null) {
//                    List<TimeSegment> segmentsCopy = new ArrayList<>(detail.getUsedSegment());
//                    detailCopy.setUsedSegment(segmentsCopy);
//                }
//
//                detailsCopy.add(detailCopy);
//            }
//            copy.setGeneDetails(detailsCopy);
//        }
//
//        // 深拷贝 TargetFinishedOperationId 列表
//        if (source.getTargetFinishedOperationId() != null) {
//            copy.setTargetFinishedOperationId(new ArrayList<>(source.getTargetFinishedOperationId()));
//        }
//
//        return copy;
//    }
//
//    /**
//     * 在排产前标记锁定期工单占用的设备时间段
//     * 将锁定期工单占用的设备时间段标记为不可用，避免新工单与锁定期工单冲突
//     *
//     * @param machines 设备列表
//     * @param baseTime 基准时间
//     */
//    private void markLockedOrdersOccupiedTime(List<Machine> machines, LocalDateTime baseTime) {
//        try {
//            // 1. 获取时间配置
//            ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
//            if (timeConfig == null || timeConfig.getBaseTime() == null) {
//                log.warn("未找到ApsTimeConfig配置，跳过标记锁定期设备占用");
//                return;
//            }
//
//            long freezeSeconds = timeConfig.getFreezeDate() != null ? timeConfig.getFreezeDate().longValue() : 0;
//            if (freezeSeconds <= 0) {
//                log.info("冻结期秒数为{}，跳过标记锁定期设备占用", freezeSeconds);
//                return;
//            }
//
//            // 2. 计算锁定期范围
//            LocalDateTime lockStartTime = baseTime;
//            LocalDateTime lockEndTime = baseTime.plusSeconds(freezeSeconds);
//
//            log.info("开始标记锁定期设备占用时间段，锁定期范围: {} 到 {}", lockStartTime, lockEndTime);
//
//            // 3. 从Dispatch表查询锁定期内的工单
//            List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
//                    .ge(Dispatch::getBeginTime, lockStartTime)
//                    .le(Dispatch::getBeginTime, lockEndTime)
//                    .eq(Dispatch::getIsDeleted, 0L)
//                    .isNotNull(Dispatch::getEquipId)
//                    .isNotNull(Dispatch::getBeginTime)
//                    .isNotNull(Dispatch::getEndTime)
//                    .list();
//
//            if (frozenDispatches.isEmpty()) {
//                log.info("没有锁定期工单需要标记设备占用");
//                return;
//            }
//
//            log.info("查询到 {} 个锁定期工单，开始标记设备占用", frozenDispatches.size());
//
//            // 4. 按设备分组
//            Map<Long, List<Dispatch>> dispatchByMachine = frozenDispatches.stream()
//                    .collect(Collectors.groupingBy(Dispatch::getEquipId));
//
//            // 5. 为每个设备标记占用时间段
//            int markedCount = 0;
//            for (Map.Entry<Long, List<Dispatch>> entry : dispatchByMachine.entrySet()) {
//                Long machineId = entry.getKey();
//                List<Dispatch> dispatches = entry.getValue();
//
//                // 查找对应的Machine对象
//                Machine machine = machines.stream()
//                        .filter(m -> m.getId() == machineId)
//                        .findFirst()
//                        .orElse(null);
//
//                if (machine == null) {
//                    log.warn("未找到设备 {}，跳过标记", machineId);
//                    continue;
//                }
//
//                // 为该设备的每个锁定期工单创建占用时间段
//                for (Dispatch dispatch : dispatches) {
//                    LocalDateTime dispatchStart = dispatch.getBeginTime();
//                    LocalDateTime dispatchEnd = dispatch.getEndTime();
//
//                    // 只标记结束时间在baseTime之后的工单（这些会占用未来的设备时间）
//                    if (dispatchEnd.isAfter(baseTime)) {
//                        // 如果开始时间在baseTime之前，则从baseTime开始标记
//                        LocalDateTime occupyStart = dispatchStart.isBefore(baseTime) ? baseTime : dispatchStart;
//                        LocalDateTime occupyEnd = dispatchEnd;
//
//                        // 创建一个不可用的时间段
//                        TimeSegment occupiedSegment = new TimeSegment();
//                        occupiedSegment.setStart(occupyStart);
//                        occupiedSegment.setEnd(occupyEnd);
//                        occupiedSegment.setType(SegmentType.MAINTENANCE); // 标记为不可用
//                        occupiedSegment.setUsed(true); // 标记为已占用
//                        occupiedSegment.setHoliday(false);
//                        occupiedSegment.setEfficiency(1.0);
//
//                        // 添加到设备的可用时间段列表中
//                        if (machine.getAvailability() == null) {
//                            machine.setAvailability(new CopyOnWriteArrayList<>());
//                        }
//                        machine.getAvailability().add(occupiedSegment);
//
//                        markedCount++;
//                        log.debug("标记设备 {} 的锁定期占用时间段: {} 到 {}, 订单: {}",
//                                machineId, occupyStart, occupyEnd, dispatch.getMesCode());
//                    }
//                }
//            }
//
//            log.info("成功标记 {} 个锁定期工单的设备占用时间段", markedCount);
//
//        } catch (Exception e) {
//            log.error("标记锁定期设备占用时间段失败: {}", e.getMessage(), e);
//        }
//    }

    public Chromosome  editMachineOption(String SceneId, Entry operation,
                                         Long newMachineId) {

        Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
        if (chromosome == null || chromosome.getAllOperations() == null) {
            return chromosome;
        }

        List<Entry> operations = chromosome.getAllOperations();
        int position = IntStream.range(0, operations.size())
                .filter(i -> operations.get(i).getId() == operation.getId())
                .findFirst()
                .orElse(-1);

        if (position != -1) {
            Entry oldEntry = operations.set(position, operation);

            List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();
            if (globalOpList != null) {
                globalOpList.stream()
                        .filter(opInfo -> opInfo.getOp() != null && opInfo.getOp().getId() == oldEntry.getId())
                        .forEach(opInfo -> opInfo.setOp(operation));
            }
        }
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);
//        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);


        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        WriteScheduleSummary(chromosome);
        ScheduleOperation.editMachineOption(chromosome,operation,newMachineId,globalParam);
        WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }


    public Chromosome EditOperation(String SceneId, Entry operation) {
        Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
        if (chromosome == null || chromosome.getAllOperations() == null) {
            return chromosome;
        }

        List<Entry> operations = chromosome.getAllOperations();
        int position = IntStream.range(0, operations.size())
                .filter(i -> operations.get(i).getId() == operation.getId())
                .findFirst()
                .orElse(-1);

        if (position != -1) {
            Entry oldEntry = operations.set(position, operation);

            List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();
            if (globalOpList != null) {
                globalOpList.stream()
                        .filter(opInfo -> opInfo.getOp() != null && opInfo.getOp().getId() == oldEntry.getId())
                        .forEach(opInfo -> opInfo.setOp(operation));
            }
        }
//        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return redecodeChromosome(chromosome, SceneId);
    }

    public Chromosome EditOrder(String SceneId, Order order) {
        Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
        if (chromosome == null || chromosome.getOrders() == null) {
            return chromosome;
        }

        List<Order> orders = chromosome.getOrders();
        int position = IntStream.range(0, orders.size())
                .filter(i -> orders.get(i).getId() == order.getId())
                .findFirst()
                .orElse(-1);

        if (position != -1) {
            orders.set(position, order);
        }

        orderSortService.initializeFieldExtractors();
        OrderSortRule rule = scheduleStrategyService.createMultiConditionRule(orders);
        orderSortService.assignPriority(orders, rule);

        updateOrderRelatedEntries(chromosome, order);
//        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return redecodeChromosome(chromosome,SceneId);
    }





    public Chromosome editOrder(Chromosome chromosome,String SceneId, Order order) {


        List<Order> orders = chromosome.getOrders();

        orderSortService.initializeFieldExtractors();
        OrderSortRule rule = scheduleStrategyService.createMultiConditionRule(orders);
        orderSortService.assignPriority(orders, rule);

        updateOrderRelatedEntries(chromosome, order);
//        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return redecodeChromosome(chromosome,SceneId);
    }


    public Chromosome editOperation(Chromosome chromosome,String SceneId, Entry operation) {



        List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();
        if (globalOpList != null) {
            globalOpList.stream()
                    .filter(opInfo -> opInfo.getOp() != null && opInfo.getOp().getId() == operation.getId())
                    .forEach(opInfo -> opInfo.setOp(operation));
        }
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.editMachineOption(chromosome,operation,operation.getSelectMachineID(),globalParam);

        return redecodeChromosome(chromosome,SceneId);
    }




    public Chromosome  editMachine(Chromosome chromosome,String SceneId, Entry operation) {






        List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();
        if (globalOpList != null) {
            globalOpList.stream()
                    .filter(opInfo -> opInfo.getOp() != null && opInfo.getOp().getId() == operation.getId())
                    .forEach(opInfo -> opInfo.setOp(operation));
        }

//        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return redecodeChromosome(chromosome, SceneId);
    }



    public void UnlockStartTime(String sceneId, int opId) {
        Chromosome chromosome = _sceneService.loadChromosomeFromFile(sceneId);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        ScheduleOperation.UnlockStartTime(chromosome, opId);

        _sceneService.saveChromosomeToFile(chromosome, sceneId);
    }


    public void unlockStartTime(Chromosome chromosome, int opId) {

        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        ScheduleOperation.UnlockStartTime(chromosome, opId);
    }


    /**
     * 更新订单相关的所有Entry的数量和优先级
     */
    private void updateOrderRelatedEntries(Chromosome chromosome, Order order) {
        // 更新所有操作中的Entry
        List<Entry> allOperations = chromosome.getAllOperations();
        if (allOperations != null) {
            allOperations.stream()
                    .filter(entry -> entry.getOrderId() != null && entry.getOrderId().equals(order.getOrderId()))
                    .forEach(entry -> {
                        entry.setQuantity(order.getQuantity());
                        entry.setPriority(order.getActualPriority());
                    });
        }

        // 更新GlobalOperationInfo中的Entry
        List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();
        if (globalOpList != null) {
            globalOpList.stream()
                    .map(GlobalOperationInfo::getOp)
                    .filter(entry -> entry != null && entry.getOrderId() != null && entry.getOrderId().equals(order.getOrderId()))
                    .forEach(entry -> {
                        entry.setQuantity(order.getQuantity());
                        entry.setPriority(order.getActualPriority());
                    });
        }

        // 更新调度结果中的数量（关键：处理锁定期工单）
        List<GAScheduleResult> results = chromosome.getResult();
        if (results != null) {
            results.stream()
                    .filter(result -> result.getOrderId() != null && result.getOrderId().equals(order.getOrderId()))
                    .forEach(result -> {
                        result.setQuantity(order.getQuantity());
                        log.info("更新调度结果中的订单数量: OrderId={}, 新数量={}", order.getOrderId(), order.getQuantity());
                    });
        }
    }

    /**
     * 重新解码染色体
     */
    private Chromosome redecodeChromosome(Chromosome chromosome,String SceneId)  {
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);
        ScheduleOperationService scheduleOperation = new ScheduleOperationService(materialRequirementService,this);
        scheduleOperation.redecode(chromosome, chromosome.getBaseTime(), globalParam);
//        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return chromosome;
    }

    public Chromosome  ChangeBaseTime(String SceneId,LocalDateTime BaseTime) {
        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        if (chromosome == null || chromosome.getAllOperations() == null) {
            return chromosome; // 直接返回，空值由上层处理
        }

        chromosome.setBaseTime(BaseTime);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);
        ScheduleOperation.redecode(chromosome,chromosome.getBaseTime(), globalParam);

        return  chromosome;
    }
    public Chromosome  Drag(String SceneId,List<Integer> opId,  int targetopId,Boolean isfront,
                            Long newMachineId) {


        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        // 拖拽前清理历史工单在设备上的静态占位段，确保历史工单移动后可释放产能
        int releasedCount = releaseLockedOccupancyForDrag(chromosome);



        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        //  WriteScheduleSummary(chromosome);
        ScheduleOperation.dragOperation(chromosome,opId,targetopId,isfront,newMachineId, globalParam);
        // WriteScheduleSummary(chromosome);

        saveChromosomeOrThrow(chromosome, SceneId, "drag operation");
        return  chromosome;
    }
    /**
     * 释放历史工单占用段（拖拽前调用）
     */
    private int releaseLockedOccupancyForDrag(Chromosome chromosome) {
        if (chromosome == null || chromosome.getInitMachines() == null || chromosome.getInitMachines().isEmpty()) {
            return 0;
        }

        int releasedCount = 0;
        for (Machine machine : chromosome.getInitMachines()) {
            if (machine == null || machine.getAvailability() == null || machine.getAvailability().isEmpty()) {
                continue;
            }

            for (TimeSegment segment : machine.getAvailability()) {
                if (segment == null) {
                    continue;
                }

                boolean lockedOccupyKey = segment.getKey() != null && segment.getKey().startsWith("LOCKED_OCCUPY_");
                boolean usedRegularOrMaintenance = segment.isUsed()
                        && (segment.getType() == SegmentType.REGULAR || segment.getType() == SegmentType.MAINTENANCE);

                if (lockedOccupyKey || usedRegularOrMaintenance) {
                    releasedCount++;
                    segment.setUsed(false);
                    segment.setType(SegmentType.REGULAR);
                    if (lockedOccupyKey) {
                        segment.setKey(UUID.randomUUID().toString());
                    }
                }
            }

            machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
        }

        return releasedCount;
    }
    private String getStringValue(Map<String, Object> data, String key) {
        Object value = data == null ? null : data.get(key);
        if (value == null) {
            return null;
        }
        String text = String.valueOf(value).trim();
        return text.isEmpty() ? null : text;
    }

    private String getFirstStringValue(Map<String, Object> data, String... keys) {
        if (keys == null) {
            return null;
        }
        for (String key : keys) {
            String value = getStringValue(data, key);
            if (value != null) {
                return value;
            }
        }
        return null;
    }

    private LocalDateTime parseOrderDateTime(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        String text = String.valueOf(value).trim();
        if (text.isEmpty()) {
            return null;
        }
        try {
            return LocalDateTime.parse(text);
        } catch (DateTimeParseException ignored) {
            return OffsetDateTime.parse(text).toLocalDateTime();
        }
    }

    private Integer parseOrderPriority(Object value) {
        if (value == null || String.valueOf(value).trim().isEmpty()) {
            return 1;
        }
        return Integer.valueOf(String.valueOf(value).trim());
    }

    private void applyNewOrderPayload(ProdLaunchOrder launchOrder, Map<String, Object> newOrderData) {
        if (launchOrder == null || newOrderData == null) {
            return;
        }

        String materialCode = getFirstStringValue(newOrderData, "mmcode", "materialCode");
        if (materialCode != null) {
            launchOrder.setMaterialCode(materialCode);
        }
        String materialName = getFirstStringValue(newOrderData, "mmname", "materialName");
        if (materialName != null) {
            launchOrder.setMaterialName(materialName);
        }
        String serie = getFirstStringValue(newOrderData, "series", "seriesName", "serie");
        if (serie != null) {
            launchOrder.setSerie(serie);
        }
        String groupCode = getFirstStringValue(newOrderData, "zone", "zoneid", "groupCode");
        if (groupCode != null) {
            launchOrder.setGroupCode(groupCode);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Chromosome InsertOrderAuto(String sceneId, Map<String, Object> newOrderData) {
        if (newOrderData == null) {
            throw new RuntimeException("newOrder 不能为空");
        }

        String orderCode = getStringValue(newOrderData, "orderCode");
        String materialId = getStringValue(newOrderData, "materialId");
        Object qtyObj = newOrderData.get("quantity");
        if (orderCode == null || orderCode.trim().isEmpty()) {
            throw new RuntimeException("orderCode 不能为空");
        }
        if (materialId == null || materialId.trim().isEmpty()) {
            throw new RuntimeException("materialId 不能为空");
        }
        if (qtyObj == null) {
            throw new RuntimeException("quantity 不能为空");
        }
        Double quantity = Double.valueOf(String.valueOf(qtyObj));
        LocalDateTime startDate = parseOrderDateTime(
                getFirstStringValue(newOrderData, "startDate", "begintime", "beginTime"));
        LocalDateTime endDate = parseOrderDateTime(
                getFirstStringValue(newOrderData, "endDate", "deliverytime", "deliveryTime"));
        Integer priority = parseOrderPriority(
                getFirstStringValue(newOrderData, "priority", "prioritry"));

        // 1. 创建新订单（沿用现有创建逻辑）
        R<String> insertResp = lanuchService.insertOrder(sceneId, orderCode, materialId,
                startDate, endDate, priority, quantity);
        String insertMsg = insertResp != null ? insertResp.getData() : null;
        if (insertMsg == null || insertMsg.trim().isEmpty()) {
            throw new RuntimeException("创建订单失败：未返回订单ID");
        }

        String newOrderId = insertMsg;
        if (insertMsg.contains("订单ID:")) {
            newOrderId = insertMsg.substring(insertMsg.indexOf("订单ID:") + 5).trim();
        }

        // 2. 读取场景排产结果
        Chromosome chromosome = _sceneService.loadChromosomeFromFile(sceneId);
        if (chromosome == null) {
            throw new RuntimeException("场景不存在或排产结果未初始化");
        }

        // 3. 查询新订单及其工序
        ProdLaunchOrder newLaunchOrder = _prodLaunchOrderService.lambdaQuery()
                .eq(ProdLaunchOrder::getSceneId, sceneId)
                .eq(ProdLaunchOrder::getOrderId, newOrderId)
                .one();
        if (newLaunchOrder == null) {
            throw new RuntimeException("新订单不存在：" + newOrderId);
        }
        applyNewOrderPayload(newLaunchOrder, newOrderData);
        _prodLaunchOrderService.updateById(newLaunchOrder);

        List<ProdProcessExec> newProcessExecs = _prodProcessExecService.lambdaQuery()
                .eq(ProdProcessExec::getSceneId, sceneId)
                .eq(ProdProcessExec::getOrderId, newOrderId)
                .orderByAsc(ProdProcessExec::getTaskSeq)
                .list();
        if (newProcessExecs == null || newProcessExecs.isEmpty()) {
            throw new RuntimeException("新订单没有工序：" + newOrderId);
        }

        // 3.1 查询新工序对应设备（与InitEntrys对齐：execId -> prod_equipment）
        List<String> execIds = newProcessExecs.stream()
                .map(ProdProcessExec::getExecId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        List<ProdEquipment> newProdEquipments = execIds.isEmpty()
                ? new ArrayList<>()
                : _prodEquipmentService.lambdaQuery()
                .eq(ProdEquipment::getSceneId, sceneId)
                .in(ProdEquipment::getExecId, execIds)
                .list();

        if (newProdEquipments == null || newProdEquipments.isEmpty()) {
            throw new RuntimeException("自动插单失败：新工单未生成可选设备，请检查PROD_EQUIPMENT");
        }
        // 4. 计算锚点时间：基准时间 + 冻结期
        LocalDateTime baseTime = chromosome.getBaseTime();
        LambdaQueryWrapper<ApsTimeConfig> queryWrapper = new LambdaQueryWrapper<>();
        ApsTimeConfig apsTimeConfig = apsTimeConfigMapper.selectOne(queryWrapper);
        long freezeSeconds = 0L;
        if (apsTimeConfig != null && apsTimeConfig.getFreezeDate() != null) {
            freezeSeconds = apsTimeConfig.getFreezeDate().longValue();
        }
        if (apsTimeConfig != null && apsTimeConfig.getBaseTime() != null) {
            baseTime = apsTimeConfig.getBaseTime();
        }
        if (baseTime == null) {
            throw new RuntimeException("自动插单失败：排产基准时间为空");
        }
        // 自动插单后会重解码，染色体里的基准时间也要同步，避免后续按空基准时间计算。
        chromosome.setBaseTime(baseTime);
        LocalDateTime anchorTime = baseTime.plusSeconds(Math.max(freezeSeconds, 0L));

        // 5. 自动插单（占位后推 + 空挡前移）
        GlobalParam globalParam = buildGlobalParamFromSnapshot(sceneId, chromosome, true);
        ensureAutoInsertMachines(chromosome, newProdEquipments, baseTime, globalParam);
        ScheduleOperationService scheduleOperation = new ScheduleOperationService(materialRequirementService, this);
        scheduleOperation.InsertOrderAuto(
                chromosome,
                newOrderId,
                newLaunchOrder,
                newProcessExecs,
                newProdEquipments,
                anchorTime,
                globalParam
        );

        // 6. 保存
        WriteScheduleSummary(chromosome);
        saveChromosomeOrThrow(chromosome, sceneId, "auto insert order");

        return chromosome;
    }

    private void ensureAutoInsertMachines(Chromosome chromosome, List<ProdEquipment> newProdEquipments,
                                          LocalDateTime baseTime, GlobalParam globalParam) {
        if (chromosome == null || newProdEquipments == null || newProdEquipments.isEmpty()) {
            return;
        }
        if (chromosome.getMachines() == null) {
            chromosome.setMachines(new ArrayList<>());
        }
        if (chromosome.getInitMachines() == null) {
            chromosome.setInitMachines(new ArrayList<>());
        }

        Set<Long> existingMachineIds = chromosome.getMachines().stream()
                .filter(Objects::nonNull)
                .map(Machine::getId)
                .collect(Collectors.toSet());
        Set<Long> requiredMachineIds = newProdEquipments.stream()
                .map(ProdEquipment::getEquipId)
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        requiredMachineIds.removeAll(existingMachineIds);
        if (requiredMachineIds.isEmpty()) {
            return;
        }

        // 自动插单可能引入当前场景原来没有用到的设备，需要按设备日历补进染色体设备池。
        MachineSchedulerService machineScheduler = new MachineSchedulerService(baseTime);
        List<Machine> allMachines = globalParam != null && !globalParam.isIsUseCalendar()
                ? _routingDataService.InitNoCalendarToAllMachines(machineScheduler, baseTime)
                : _routingDataService.InitCalendarToAllMachines(machineScheduler, baseTime);
        Map<Long, Machine> machineById = allMachines.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(Machine::getId, Function.identity(), (existing, replacement) -> existing));

        List<Long> missingMachineIds = new ArrayList<>();
        for (Long machineId : requiredMachineIds) {
            Machine machine = machineById.get(machineId);
            if (machine == null) {
                missingMachineIds.add(machineId);
                continue;
            }
            Machine machineCopy = ProductionDeepCopyUtil.deepCopy(machine, Machine.class);
            Machine initMachineCopy = ProductionDeepCopyUtil.deepCopy(machine, Machine.class);
            chromosome.getMachines().add(machineCopy);
            chromosome.getInitMachines().add(initMachineCopy);
        }

        if (!missingMachineIds.isEmpty()) {
            throw new RuntimeException("自动插单失败：新工序设备未找到设备资源/日历配置: " + missingMachineIds);
        }
        log.info("自动插单补充设备到当前排产设备池: sceneId={}, machineIds={}", chromosome.getScenarioID(), requiredMachineIds);
    }

    public Chromosome  Move(String SceneId,List<Integer> opId, LocalDateTime newStartTime,
                            Long newMachineId,int lockStartTime) {


        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);


        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        //  WriteScheduleSummary(chromosome);
        ScheduleOperation.moveOperation(chromosome,opId, (int)ChronoUnit.SECONDS.between(chromosome.getBaseTime(), newStartTime),newMachineId, globalParam, lockStartTime);
        // WriteScheduleSummary(chromosome);

        saveChromosomeOrThrow(chromosome, SceneId, "move operation");
        return  chromosome;
    }




    public Chromosome  lock(Chromosome chromosome,List<Integer> opId, LocalDateTime newStartTime,
                            Long newMachineId,int lockStartTime) {


        GlobalParam globalParam = buildGlobalParamFromSnapshot(chromosome);



        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        //  WriteScheduleSummary(chromosome);
        ScheduleOperation.moveOperation(chromosome,opId, (int)ChronoUnit.SECONDS.between(chromosome.getBaseTime(), newStartTime),newMachineId, globalParam, lockStartTime);
        // WriteScheduleSummary(chromosome);

        return  chromosome;
    }


    public void   Redecode(String SceneId)
    {
        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        //  WriteScheduleSummary(chromosome);


        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);
        ScheduleOperation.redecode(chromosome, chromosome.getBaseTime(), globalParam);
        //   WriteScheduleSummary(chromosome);
    }



    public Chromosome  SpiltOperation(String SceneId,int opId,Double[] splitCounts) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        //this.baseTime=param.getBaseTime();
        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.SpiltOperation(chromosome,opId,splitCounts, globalParam);
        WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }

    public Chromosome  DelOperation(String SceneId,int opId) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        //this.baseTime=param.getBaseTime();
        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.DelOperation(chromosome,opId, globalParam);
        // WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }

    public Chromosome  DelOrder(String SceneId,String orderId) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        //this.baseTime=param.getBaseTime();
        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.DelOrder(chromosome,orderId, globalParam);
        // WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }




    public Chromosome  LockOperation(String SceneId,int opId,boolean isLocked) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        //this.baseTime=param.getBaseTime();
        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.LockOperation(chromosome,opId,isLocked, globalParam);
        //WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }

    public Chromosome  SpiltOrder(String SceneId,String orderId,Double[] splitCounts) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        //this.baseTime=param.getBaseTime();
        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.SpiltOrder(chromosome,orderId,splitCounts, globalParam);
        WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }
    public void redecode(String SceneId) {
        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        ScheduleOperation.redecode(chromosome, chromosome.getBaseTime(), globalParam);
    }


    /**
     * 插单功能：在指定订单后插入新订单
     * 步骤1：先将新订单数据插入数据库
     * 步骤2：使用类似复制订单的方式将新订单加入排产
     *
     * @param SceneId 场景ID
     * @param afterOrderId 插入位置订单ID（新订单将排在此订单后面）
     * @param newOrderData 新订单数据
     * @return 更新后的Chromosome
     */
    public Chromosome InsertOrder(String SceneId, String afterOrderId, Map<String, Object> newOrderData) {
        // 步骤1：调用LanuchService的insertOrder方法，将新订单插入数据库
        String orderCode = (String) newOrderData.get("orderCode");
        String materialId = (String) newOrderData.get("materialId");
        Double quantity = ((Number) newOrderData.get("quantity")).doubleValue();

        LocalDateTime startDate = null;
        LocalDateTime endDate = null;
        Integer priority = 1;

        if (newOrderData.containsKey("startDate")) {
            startDate = LocalDateTime.parse((String) newOrderData.get("startDate"));
        }
        if (newOrderData.containsKey("endDate")) {
            endDate = LocalDateTime.parse((String) newOrderData.get("endDate"));
        }
        if (newOrderData.containsKey("priority")) {
            priority = ((Number) newOrderData.get("priority")).intValue();
        }

        // 调用insertOrder插入数据库
        R<String> insertResult = lanuchService.insertOrder(SceneId, orderCode, materialId,
                startDate, endDate, priority, quantity);

//        if (!insertResult.isSuccess()) {
//            throw new RuntimeException("插单失败: " + insertResult.getMsg());
//        }
//
        // 从返回消息中提取新订单ID
        String message = insertResult.getData();
        String newOrderId = message.substring(message.indexOf("订单ID: ") + 6);

        log.info("新订单已插入数据库，订单ID: {}", newOrderId);

        // 步骤2：使用类似SpiltOrder的方式，将新订单加入排产
        // 这里需要重新加载场景，因为数据库已经有新订单了
        // 然后使用类似复制的逻辑，将新订单排在afterOrderId后面

        Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        // 从数据库加载新插入的订单及其工序
        ProdLaunchOrder newLaunchOrder = _prodLaunchOrderService.lambdaQuery()
                .eq(ProdLaunchOrder::getSceneId, SceneId)
                .eq(ProdLaunchOrder::getOrderId, newOrderId)
                .one();

        if (newLaunchOrder == null) {
            throw new RuntimeException("未找到新插入的订单: " + newOrderId);
        }

        // 加载新订单的工序
        List<ProdProcessExec> newProcessExecs = _prodProcessExecService.lambdaQuery()
                .eq(ProdProcessExec::getSceneId, SceneId)
                .eq(ProdProcessExec::getOrderId, newOrderId)
                .orderBy(true, true, ProdProcessExec::getTaskSeq)
                .list();

        if (newProcessExecs.isEmpty()) {
            throw new RuntimeException("新订单没有工序: " + newOrderId);
        }

        log.info("加载新订单: OrderId={}, OrderCode={}, 工序数={}",
                newOrderId, newLaunchOrder.getOrderCode(), newProcessExecs.size());

        // 调用ScheduleOperationService的方法将新订单加入排产
        // 设备配置将从插入位置的订单复制，不需要单独加载
        ScheduleOperationService scheduleOperation = new ScheduleOperationService(materialRequirementService, this);
        scheduleOperation.InsertOrder(chromosome, afterOrderId, newOrderId, newLaunchOrder, newProcessExecs, globalParam);

        WriteScheduleSummary(chromosome);
        saveChromosomeOrThrow(chromosome, SceneId, "insert order");
        return chromosome;
    }

    private void saveChromosomeOrThrow(Chromosome chromosome, String sceneId, String operationName) {
        if (!_sceneService.saveChromosomeToFile(chromosome, sceneId)) {
            throw new RuntimeException(operationName + " failed: unable to save schedule version");
        }
    }

    public Chromosome  MergeOrder(String SceneId,String sourceorderId,String targetorderId) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        //this.baseTime=param.getBaseTime();
        //  WriteScheduleSummary(chromosome);
        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.MergeOrder(chromosome,sourceorderId,targetorderId, globalParam);
        WriteScheduleSummary(chromosome);
        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }

    public Chromosome  AddMaintenanceWindow(String SceneId, Long machineId, MaintenanceWindow maintenanceWindow) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);



        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.AddMaintenanceWindow(chromosome,machineId,maintenanceWindow, globalParam);
        // WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }

    public Chromosome  DelMaintenanceWindow(String SceneId, Long machineId,String maintenanceId) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);



        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.DelMaintenanceWindow(chromosome,machineId,maintenanceId, globalParam);
        // WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return  chromosome;
    }

    public Chromosome DelMaintenanceWindowBatch(String SceneId, Long machineId, List<String> maintenanceIds) {
        Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);

        ScheduleOperationService ScheduleOperation = new ScheduleOperationService(materialRequirementService,this);

        ScheduleOperation.DelMaintenanceWindowBatch(chromosome, machineId, maintenanceIds, globalParam);
        // WriteScheduleSummary(chromosome);

        _sceneService.saveChromosomeToFile(chromosome, SceneId);
        return chromosome;
    }

    public List<MaintenanceWindow>  GetMaintenanceWindow(String SceneId, Long machineId, MaintenanceWindow maintenanceWindow) {

        Chromosome chromosome= _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = buildGlobalParamFromSnapshot(SceneId, chromosome);



        ScheduleOperationService ScheduleOperation=new ScheduleOperationService(materialRequirementService,this);

        List<MaintenanceWindow> maintenanceWindowList= ScheduleOperation.GetMaintenanceWindow(chromosome,machineId);
        // WriteScheduleSummary(chromosome);

        return  maintenanceWindowList;
    }



    //场景回退前进
    public Chromosome moveChromosome(String sceneId,Integer version)
    {
        return  _sceneService.moveChromosome( sceneId, version);
    }






    //场景下所有操作版本
    public SceneChromsome getSceneChromsome(String sceneId)
    {
        return  _sceneService.getSceneChromsome( sceneId);
    }



    public Chromosome revertVersion(String sceneId,Integer version)
    {
        return  _sceneService.revertVersion( sceneId, version);
    }
    public void testSceneChromsome(String sceneId)
    {
        Chromosome chromosome=new  Chromosome();

        _sceneService.saveChromosomeToFile(chromosome,sceneId);
    }





    public Chromosome  schedule(String SceneId) {
        try {
            FileHelper.writeLogFile("schedule-----------开始-----------"+SceneId);

            ScheduleParams param = InitScheduleParams();




            // 1. 读取数据
            //  List<Machine> machines = loadData("machines.json", Machine.class);
            //  List<Product> products = loadData("products.json", Product.class);
            // List<Order> orders = loadData("orders.json", Order.class);




            List<ProdEquipment> ProdEquipments=  _prodEquipmentService.lambdaQuery()
                    .eq(ProdEquipment::getSceneId,SceneId)
                    .list();
            GlobalParam globalParam = buildInitialGlobalParam(SceneId, null, null, null);
            List<ProdLaunchOrder> ProdLaunchOrders=  _prodLaunchOrderService.lambdaQuery()
                    .eq(ProdLaunchOrder::getSceneId,SceneId)
                    .list();
            // 3. 创建调度服务
            MachineSchedulerService machineScheduler = new MachineSchedulerService(
                    param.getBaseTime());
            List<Machine> machines= InitCalendarToAllMachines(SceneId, ProdEquipments,machineScheduler,globalParam.isIsUseCalendar());
            // 3. 构建订单-工序数据

            List<Order> orders=InitOrder(ProdLaunchOrders);

            List<Material> Materials=InitMaterial();
            Map<Integer,Object> list= InitEntrys(SceneId,ProdEquipments,orders);
            List<Entry> entrys=(List<Entry>)list.get(1);
            List<GroupResult> entryRel=(List<GroupResult>)list.get(2);
            entrys.sort(
                    Comparator.comparing(Entry::getPriority)
            );
            Set<Long> machineIds=(Set<Long>)list.get(3);

            machines= machines.stream().filter(t->machineIds.contains(t.getId())).collect(Collectors.toList());


            // 5. 执行调度算法
            GeneticAlgorithm scheduler =new GeneticAlgorithm(globalParam,machines,orders,  materialRequirementService.GetMaterialListToMap(Materials),null,machineScheduler,entryRel,materialRequirementService,_sceneService,SceneId); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
            param.initAdaptiveParams(entrys.size());
            double[] customWeights = new double[] { 0.4, 0.1, 0.1, 0.1, 0.3 }; // 延迟时间权重提升到0.5
            //完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
            scheduler.Init();
            Chromosome  chromosomes =scheduler.Run(param,entrys);
            KpiCalculator kpiCalculator=new KpiCalculator(chromosomes);
            kpiCalculator.calculatekpi();
            chromosomes.setScenarioID(SceneId);
            chromosomes.setBaseTime(param.getBaseTime());
            // chromosomes.setOperatRel(new CopyOnWriteArrayList<>(entryRel));
            // 保存chromosomes到文件
            saveGlobalParamSnapshot(chromosomes, globalParam);
            boolean saved = _sceneService.saveChromosomeToFile(chromosomes, SceneId);
            if (!saved) {
                throw new BusinessException("排产计算结果保存失败，请稍后重试或联系管理员");
            }

            // Chromosomes.forEach(this::WriteScheduleSummary);
            FileHelper.writeLogFile("schedule-----------结束-----------"+SceneId);
            return chromosomes;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessException("排产计算失败，请检查场景数据后重试", e);
        }
    }


    public void WriteScheduleSummary(Chromosome schedule) {
        //WriteOperationIntegrityLog(schedule);
        // 写入日志
        FileHelper.writeLogFile("\n=== Schedule Summary === ");
        FileHelper.writeLogFile(String.format("ID: %s", schedule.getID()));
        FileHelper.writeLogFile(String.format("ID: %s", schedule.getGeneStr()));

        FileHelper.writeLogFile(String.format("Operation: %s", schedule.getOperationStr()));
        FileHelper.writeLogFile(String.format("Makespan: %f minutes", schedule.getMakespan()));
        FileHelper.writeLogFile(String.format("Total Tardiness: %f hours", schedule.getDelayTime()));
        FileHelper.writeLogFile(String.format("Setup Time: %f minutes", schedule.getTotalChangeoverTime()));
        FileHelper.writeLogFile(String.format("Flow Time: %f minutes", schedule.getTotalFlowTime()));
        FileHelper.writeLogFile(String.format("Machine Load Balance: %.2f%%", schedule.getMachineLoadStd() * 100));
        FileHelper.writeLogFile("-------------------------");

        // 按订单分组写入
        Map<Integer, List<GAScheduleResult>> orderGroups = schedule.getResult().stream()
                .collect(Collectors.groupingBy(GAScheduleResult::getGroupId));

        for (Map.Entry<Integer, List<GAScheduleResult>> group : orderGroups.entrySet()) {
            List<GAScheduleResult> sortedJobs = group.getValue().stream()
                    .sorted(Comparator.comparingInt(GAScheduleResult::getOperationId))
                    .collect(Collectors.toList());

            Map<Integer, Order> orders = schedule.getOrders().stream()
                    .collect(Collectors.toMap(
                            Order::getId,
                            // 2. Value映射：Material → Material
                            order -> order
                    ));
            for (GAScheduleResult job : sortedJobs) {
                StringBuilder sb = new StringBuilder();
                String TargetFinishedOperationIds="";
                if(job.getTargetFinishedOperationId()!=null)
                {
                    TargetFinishedOperationIds= job.getTargetFinishedOperationId().stream()
                            .map(String::valueOf) // 把每个Integer转成String
                            .collect(Collectors.joining(","));
                }
                Order order=orders.get(job.getGroupId());
                String orderDueDate = order != null && order.getDueDate() != null
                        ? order.getDueDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                        : "";
                sb.append(String.format(
                        "[%d-%d]:[%s-%s] Order %d,OrderID %s,OrderDueDate %s, Machine %d, Operation %d, Quantity %.1f, processingTime %.1f, 前处理 %d, 后处理 %d, 离散参数 %d, bomtime %s,TargetOperationId %s",
                        job.getStartTime(),
                        job.getEndTime(),
                        ConvertTime(job.getStartTime()),
                        ConvertTime(job.getEndTime()),
                        job.getGroupId(),
                        job.getOrderId(),
                        orderDueDate,
                        job.getMachineId(),
                        job.getOperationId(),
                        job.getQuantity(),
                        job.getProcessingTime(),
                        job.getPreTime(),
                        job.getTeardownTime(),
                        job.getChangeOverTime(),
                        ConvertTime(job.getBomTime()),
                        TargetFinishedOperationIds

                ));
if(job.getGeneDetails()!=null)
{
    for (ScheduleResultDetail d : job.getGeneDetails()) {
        sb.append(String.format(
                "\n\t\t\t\t\t\t\t\t\t\t [%d-%d]:[%s-%s] %d---%d",
                d.getStartTime(),
                d.getEndTime(),
                ConvertTime(d.getStartTime()),
                ConvertTime(d.getEndTime()),
                d.getEndTime() - d.getStartTime(),d.isChangeOverTime()?1:0
        ));
    }
}
                // 追加基因详情


                FileHelper.writeLogFile(sb.toString());

            }
            FileHelper.writeLogFile("");
        }
    }

    private void WriteOperationIntegrityLog(Chromosome schedule) {
        if (schedule == null) {
            return;
        }

        List<Entry> allOperations = schedule.getAllOperations() == null
                ? Collections.emptyList()
                : schedule.getAllOperations();
        List<GAScheduleResult> result = schedule.getResult() == null
                ? Collections.emptyList()
                : schedule.getResult();
        String id = schedule.getID() == null ? "" : schedule.getID();

        int maxOperationId = allOperations.stream()
                .mapToInt(Entry::getId)
                .max()
                .orElse(0);
        int maxResultOperationId = result.stream()
                .mapToInt(GAScheduleResult::getOperationId)
                .max()
                .orElse(0);
        long distinctResultOperationCount = result.stream()
                .map(GAScheduleResult::getOperationId)
                .distinct()
                .count();
        int operationSequencingCount = schedule.getOperationSequencing() == null
                ? 0
                : schedule.getOperationSequencing().size();

        FileHelper.writeLogFile(id + "工序数: " + allOperations.size()
                + "----" + maxOperationId
                + "----" + operationSequencingCount);
        FileHelper.writeLogFile(id + "结果数: " + result.size()
                + "----" + maxResultOperationId
                + "----" + distinctResultOperationCount);

        Set<Integer> operationIds = allOperations.stream()
                .map(Entry::getId)
                .collect(Collectors.toSet());
        List<Integer> missingOperationIds = result.stream()
                .map(GAScheduleResult::getOperationId)
                .filter(operationId -> !operationIds.contains(operationId))
                .distinct()
                .sorted()
                .collect(Collectors.toList());
        if (missingOperationIds.isEmpty()) {
            FileHelper.writeLogFile(id + "Result中OperationId全部在allOperations中存在");
        } else {
            FileHelper.writeLogFile(id + "Result中OperationId不在allOperations中("
                    + missingOperationIds.size() + "个): " + missingOperationIds);
        }

        Map<Integer, Long> duplicateOperationIds = result.stream()
                .collect(Collectors.groupingBy(
                        GAScheduleResult::getOperationId,
                        TreeMap::new,
                        Collectors.counting()));
        List<String> duplicateDesc = duplicateOperationIds.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(entry -> entry.getKey() + "(" + entry.getValue() + "次)")
                .collect(Collectors.toList());
        if (duplicateDesc.isEmpty()) {
            FileHelper.writeLogFile(id + "Result中OperationId无重复");
        } else {
            FileHelper.writeLogFile(id + "Result中重复OperationId("
                    + duplicateDesc.size() + "个): [" + String.join(", ", duplicateDesc) + "]");
        }
    }

    private String ConvertTime(int minute) {
        return baseTime.plusSeconds(minute).format(DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"));
    }

    /**
     * 加载数据，优先从上传文件夹加载，如果不存在则从resources加载
     *
     * @param fileName 文件名
     * @param clazz    类型
     * @param <T>      泛型
     * @return 数据列表
     * @throws IOException IO异常
     */
    private <T> List<T> loadData(String fileName, Class<T> clazz) throws IOException {
        // 检查是否有上传的文件
        if (fileUploadController.isFileUploaded(fileName)) {
            String filePath = fileUploadController.getUploadedFilePath(fileName);
            return JsonFileReader.readListFromFile(filePath, clazz);
        } else {
            // 使用默认的resources文件
            return JsonFileReader.readListFromResources(fileName, clazz);
        }
    }

    /**
     * 将假期添加到所有设备的维护窗口中
     * @param machines 设备列表
     * @param holidays 假期列表
     */
    private void addHolidaysToAllMachines(List<Machine> machines, List<Holiday> holidays) {
        if (machines == null || holidays == null) {
            return;
        }

        for (Machine machine : machines) {
            // 确保维护窗口列表不为null
            if (machine.getMaintenanceWindows() == null) {
                machine.setMaintenanceWindows(new ArrayList<>());
            }

            for (Holiday holiday : holidays) {
                // 将假期转换为维护窗口并添加到设备中
                MaintenanceWindow maintenanceWindow = new MaintenanceWindow(holiday, "Holiday Period");
                machine.addMaintenanceWindow(maintenanceWindow);
            }
        }
    }

    private List<Machine> InitCalendarToAllMachines(String SceneId,List<ProdEquipment> ProdEquipments,MachineSchedulerService machineScheduler,boolean IsUseCalendar) {
        // 按设备分组
        FileHelper.writeLogFile("初始化设备日历-----------开始-------");
        ScheduleParams param = InitScheduleParams();
        List<Machine> machines=new ArrayList<>();
        if(!IsUseCalendar) {


            machines =  _routingDataService.InitNoCalendarToAllMachines(machineScheduler,param.getBaseTime());
        }else {

            machines =  _routingDataService.InitCalendarToAllMachines( machineScheduler,param.getBaseTime());

            //  List<Machine> machines = _routingDataService.InitCalendarToAllMachines(SceneId, ProdEquipments, machineScheduler, IsUseCalendar);
//            List<Machine> machines = (List<Machine>) GlobalCacheUtil.get("machines");
//            if (machines == null || machines.size() == 0) {
//
//
//                machines = (List<Machine>) redisUtils.get("machines");
//                if (machines == null || machines.size() == 0) {
//
//                    machines = InitCalendarToAllMachines();
//
//                }
//            }
//

        }
        applySceneCapacityTypeName(machines, ProdEquipments);
        FileHelper.writeLogFile("初始化设备日历-----------结束-------");

        redisUtils.set("machines",machines);
        GlobalCacheUtil.put("machines", machines, 10, TimeUnit.MINUTES);
        return machines;
    }

    private void applySceneCapacityTypeName(List<Machine> machines, List<ProdEquipment> prodEquipments) {
        if (machines == null || prodEquipments == null || prodEquipments.isEmpty()) {
            return;
        }
        Map<Long, String> capacityTypeNameByEquipId = prodEquipments.stream()
                .filter(t -> t.getEquipId() != null && t.getCapacityTypeName() != null)
                .collect(Collectors.toMap(
                        ProdEquipment::getEquipId,
                        ProdEquipment::getCapacityTypeName,
                        (existing, replacement) -> existing));
        for (Machine machine : machines) {
            String capacityTypeName = capacityTypeNameByEquipId.get(machine.getId());
            if (capacityTypeName != null) {
                machine.setCapacityTypeName(capacityTypeName);
            }
        }
    }

    public  List<Machine> InitCalendarToAllMachines ()
    {
        FileHelper.writeLogFile("初始化Redis设备日历-----------开始-------");

        ScheduleParams param = InitScheduleParams();
        MachineSchedulerService machineScheduler = new MachineSchedulerService(
                param.getBaseTime());

        List<Machine> machines = _routingDataService.InitCalendarToAllMachines( machineScheduler,param.getBaseTime());

        redisUtils.set("machines",machines);

        FileHelper.writeLogFile("初始化Redis设备日历-----------结束-------");

        return machines;
    }

    private ScheduleParams InitScheduleParams()
    {
        FileHelper.writeLogFile("初始化排产参数-----------开始-------");
        LambdaQueryWrapper<ApsTimeConfig> queryWrapper = new LambdaQueryWrapper<ApsTimeConfig>();
        Page<ApsTimeConfig> page = new Page<>(1, 1);
        ApsTimeConfig apsTimeConfig=   apsTimeConfigMapper.selectOne( queryWrapper);

        ScheduleParams param = new ScheduleParams();
        param.setBaseTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0));
        if(apsTimeConfig!=null) {
            if(apsTimeConfig.getBaseTime()!=null)
            {
                param.setBaseTime(apsTimeConfig.getBaseTime());
            }
        }
        FileHelper.writeLogFile("初始化排产参数-----------结束-------");
        return param;
    }
    private  GlobalParam InitGlobalParam()
    {
        FileHelper.writeLogFile("初始化约束-----------开始-------");

        GlobalParam globalParam=new GlobalParam();



        LambdaQueryWrapper<Config> queryWrapper = new LambdaQueryWrapper<Config>()
                .eq(Config::getComponent, "setting")
                .orderByDesc(Config::getId); // 按更新时间降序

        Page<Config> page = new Page<>(1, 1);
        configMapper.selectPage(page, queryWrapper);

// 3. 提取最后一条记录
        Config config = page.getRecords().isEmpty()
                ? null
                : page.getRecords().get(0);



        List<ConfigSetting> configs=  _configService.getComponentSettingsByPageAndNote(config.getId(),"setting");
        for (ConfigSetting c : configs) {
            if(c.getTitle().contains("日历"))
            {
                globalParam.setIsUseCalendar(c.isValue());
            }
            else if(c.getTitle().equals("设置时间"))
            {
                //是否考虑换型时间
                globalParam.set_smoothChangeOver(c.isValue());
            }

            else if(c.getTitle().contains("原材料"))
            {
                globalParam.setIsCheckMp(c.isValue());
            }
            else if(c.getTitle().contains("后台任务设置"))
            {
                //休息时间是否换型
                globalParam.set_smoothChangeOverInWeek(c.isValue());
            }
            else if(c.getTitle().contains("设置时间平滑"))
            {
                globalParam.set_smoothSetup(c.isValue());//工序的前处理是否提前
            }
            else if(c.getTitle().contains("自制件"))
            {
                globalParam.setIsCheckSf(c.isValue());
            }


        }
        FileHelper.writeLogFile("初始化约束-----------结束-------");
        return  globalParam;
    }

    private GlobalParam buildInitialGlobalParam(String sceneId, Long userId, Long baseRuleId, String userRuleId) {
        // 先拿到基础约束参数，再叠加保存的 KPI 配置，形成本次排产实际使用的 GlobalParam。
        GlobalParam globalParam = InitGlobalParam();
        Object kpiConfig = scheduleStrategyService.loadEffectiveKpiConfig(userId, baseRuleId, sceneId, userRuleId);
        globalParam.applyKpiConfig(kpiConfig);
        globalParam.setJit(scheduleStrategyService.loadEffectiveIsJit(userId, baseRuleId, sceneId, userRuleId));
        globalParam.setIsOptimizer(scheduleStrategyService.loadEffectiveIsOptimizer(userId, baseRuleId, sceneId, userRuleId));
        return globalParam;
    }

    private GlobalParam buildGlobalParamFromSnapshot(Chromosome chromosome) {
        return buildGlobalParamFromSnapshot(null, chromosome);
    }

    private GlobalParam buildGlobalParamFromSnapshot(String sceneId, Chromosome chromosome) {
        // 局部排产优先复用染色体里保存的参数快照，避免重新读取数据库或回退到默认值。
        if (chromosome != null && chromosome.getGlobalParamSnapshot() != null) {
            return chromosome.getGlobalParamSnapshot().copy();
        }

        // 没有快照时才创建默认参数，并把它补回快照，保证后续局部操作还能复用。
        GlobalParam globalParam = new GlobalParam();
        if (chromosome != null) {
            chromosome.setGlobalParamSnapshot(globalParam.copy());
        }
        return globalParam;
    }

    private GlobalParam buildGlobalParamFromSnapshot(Chromosome chromosome, boolean initConstraintFallback) {
        return buildGlobalParamFromSnapshot(null, chromosome);
    }

    private GlobalParam buildGlobalParamFromSnapshot(String sceneId, Chromosome chromosome, boolean initConstraintFallback) {
        return buildGlobalParamFromSnapshot(sceneId, chromosome);
    }

    private void saveGlobalParamSnapshot(Chromosome chromosome, GlobalParam globalParam) {
        if (chromosome != null && globalParam != null) {
            chromosome.setGlobalParamSnapshot(globalParam.copy());
        }
    }

    private List<Order> InitOrder(List<ProdLaunchOrder> ProdLaunchOrders)
    {
        return InitOrder(ProdLaunchOrders, Collections.emptyList());
    }

    private List<Order> InitOrder(List<ProdLaunchOrder> ProdLaunchOrders, List<StrategyScheduling> strategySchedulings)
    {
        orderSortService.initializeFieldExtractors();
        List<Order> orders=new ArrayList<>();
        for (ProdLaunchOrder lo : ProdLaunchOrders) {
            Order order=new Order();
            order.setMaterialCode(lo.getMaterialCode());
            order.setMaterialName(lo.getMaterialName());
            order.setSerie(lo.getSerie()==null?"":lo.getSerie());
            order.setOrderCode(lo.getOrderCode());
            order.setOrderId(lo.getOrderId());
            order.setRoutingId(lo.getRoutingId());
            order.setRoutingCode(lo.getRoutingCode());
            order.setMaterialId(lo.getMaterialId());
            order.setStartDate(lo.getStartDate());
            order.setDueDate(lo.getEndDate());
            order.setPriority(lo.getOrderPriority());
            order.setActualPriority(lo.getOrderPriority());
            order.setQuantity(lo.getQuantity());
            order.setSYQuantity(lo.getQuantity());
            orders.add(order);
        }
        // 根据策略生成订单排序规则，并把排序结果写回 Order.actualPriority。
        OrderSortRule rule = scheduleStrategyService.createMultiConditionRule(orders, strategySchedulings);

        // 执行
        orderSortService.assignPriority(orders, rule);
//        // 按照优先级排序
//        orders.sort(
//                Comparator.comparing(Order::getActualPriority)
//        );

        return orders;
    }

    /**
     * 排产前合并兼容订单：相同物料+相同工艺路线+相同系列+时间窗口重叠且交付日期相近的订单合并为一个
     * @param orders 原始订单列表
     * @param materials 物料列表（用于 maxProduction 上限校验）
     * @return entry: key=合并后的订单列表, value=originalOrderId→mergedOrder 映射表
     */
    public AbstractMap.SimpleEntry<List<Order>, Map<String, Order>> mergeOrders(List<Order> orders, List<Material> materials) {
        return mergeOrders(orders, materials, DEFAULT_MERGE_DUE_DATE_RANGE_DAYS);
    }
    /**
     * 使用 OR-Tools CP-SAT 求解最优合并方案（替代贪心算法）
     * 将兼容订单建模为 Bin Packing，最小化合并组数
     *
     * @param orders           原始订单列表
     * @param materials        物料列表
     * @param dueDateRangeDays 交付日期相差上限（天）
     * @return entry: key=合并后的订单列表, value=originalOrderId→mergedOrder 映射表
     */
    public AbstractMap.SimpleEntry<List<Order>, Map<String, Order>> mergeOrdersWithCpSat(
            List<Order> orders, List<Material> materials, int dueDateRangeDays) {
        CpSatOrderMergeService solver = new CpSatOrderMergeService();
        return solver.mergeOrders(orders, materials, dueDateRangeDays);
    }

    /**
     * @param dueDateRangeDays 允许合并的交付日期最大相差天数
     */
    public AbstractMap.SimpleEntry<List<Order>, Map<String, Order>> mergeOrders(List<Order> orders, List<Material> materials, int dueDateRangeDays) {
        if (orders == null || orders.size() <= 1) {
            return new AbstractMap.SimpleEntry<>(orders, new HashMap<>());
        }

        Map<String, Material> materialMap = buildMaterialMap(materials);
        Map<String, Order> mergeMap = new HashMap<>();
        List<Order> mergedOrders = new ArrayList<>();
        List<Order> remaining = new ArrayList<>(orders);

        while (!remaining.isEmpty()) {
            Order base = remaining.remove(0);
            List<Order> mergeGroup = new ArrayList<>();
            mergeGroup.add(base);
            double groupQty = base.getQuantity();

            Material material = materialMap.get(base.getMaterialId());
            BigDecimal maxProduction = (material != null && material.getMaxProduction() != null
                    && material.getMaxProduction().compareTo(BigDecimal.ZERO) > 0)
                    ? material.getMaxProduction() : null;

            Iterator<Order> it = remaining.iterator();
            while (it.hasNext()) {
                Order candidate = it.next();
                if (!canMerge(base, candidate, dueDateRangeDays)) {
                    continue;
                }
                double newQty = groupQty + candidate.getQuantity();
                if (maxProduction != null && BigDecimal.valueOf(newQty).compareTo(maxProduction) > 0) {
                    continue;
                }
                mergeGroup.add(candidate);
                groupQty = newQty;
                it.remove();
            }

            if (mergeGroup.size() == 1) {
                mergedOrders.add(base);
            } else {
                Order merged = createMergedOrder(mergeGroup);
                mergedOrders.add(merged);
                for (Order child : mergeGroup) {
                    mergeMap.put(child.getOrderId(), merged);
                }
            }
        }

        FileHelper.writeLogFile(String.format("订单合并完成：原始%d个 → 合并后%d个，合并组%d组",
                orders.size(), mergedOrders.size(),
                (int) mergeMap.values().stream().distinct().count()));

        return new AbstractMap.SimpleEntry<>(mergedOrders, mergeMap);
    }

    private static final int DEFAULT_MERGE_DUE_DATE_RANGE_DAYS = 7;

    private Map<String, Material> buildMaterialMap(List<Material> materials) {
        if (materials == null || materials.isEmpty()) {
            return Collections.emptyMap();
        }
        return materials.stream()
                .filter(m -> m.getId() != null)
                .collect(Collectors.toMap(Material::getId, m -> m, (existing, replacement) -> existing));
    }

    private boolean canMerge(Order a, Order b, int dueDateRangeDays) {
        if (a == null || b == null) {
            return false;
        }
        if (a.getRoutingId() == null || b.getRoutingId() == null) {
            return false;
        }
        if (!a.getRoutingId().equals(b.getRoutingId())) {
            return false;
        }
        if (a.getMaterialCode() == null || b.getMaterialCode() == null) {
            return false;
        }
        if (!a.getMaterialCode().equals(b.getMaterialCode())) {
            return false;
        }
        if (a.getSerie() == null || b.getSerie() == null) {
            return false;
        }
        if (!a.getSerie().equals(b.getSerie())) {
            return false;
        }
        if (a.isMerged() || b.isMerged()) {
            return false;
        }
        if (a.getStartDate() == null || a.getDueDate() == null
                || b.getStartDate() == null || b.getDueDate() == null) {
            return false;
        }
        boolean overlap = !a.getDueDate().isBefore(b.getStartDate())
                && !b.getDueDate().isBefore(a.getStartDate());
        if (!overlap) {
            return false;
        }
        long daysDiff = Math.abs(ChronoUnit.DAYS.between(
                a.getDueDate().toLocalDate(), b.getDueDate().toLocalDate()));
        return daysDiff <= dueDateRangeDays;
    }
    private Order createMergedOrder(List<Order> group) {
        Order merged = new Order();
        Order first = group.get(0);

        merged.setOrderId(first.getOrderId());
        merged.setOrderCode(first.getOrderCode() + "-MG");
        merged.setMaterialCode(first.getMaterialCode());
        merged.setMaterialName(first.getMaterialName());
        merged.setMaterialId(first.getMaterialId());
        merged.setSerie(first.getSerie());
        merged.setRoutingId(first.getRoutingId());
        merged.setRoutingCode(first.getRoutingCode());
        merged.setProductId(first.getProductId());
        merged.setMerged(true);

        double totalQty = group.stream().mapToDouble(Order::getQuantity).sum();
        merged.setQuantity(totalQty);
        merged.setSYQuantity(totalQty);

        LocalDateTime maxStartDate = group.stream()
                .map(Order::getStartDate)
                .filter(Objects::nonNull)
                .max(LocalDateTime::compareTo)
                .orElse(null);
        merged.setStartDate(maxStartDate);

        LocalDateTime minDueDate = group.stream()
                .map(Order::getDueDate)
                .filter(Objects::nonNull)
                .min(LocalDateTime::compareTo)
                .orElse(null);
        merged.setDueDate(minDueDate);

        int minPriority = group.stream()
                .mapToInt(Order::getPriority)
                .min()
                .orElse(first.getPriority());
        merged.setPriority(minPriority);
        merged.setActualPriority(minPriority);

        List<String> childIds = group.stream()
                .map(Order::getOrderId)
                .collect(Collectors.toList());
        merged.setMergedChildOrderIds(childIds);

        return merged;
    }
    public List<Material> InitMaterial() {
        List<Material> materials=new ArrayList<>();
        FileHelper.writeLogFile("初始化物料-----------开始-------");

//       List<MaterialInfo> materiallist=  materialInfoService.lambdaQuery()
//                .eq(MaterialInfo::getIsdeleted,0)
//               .list();

        materials= (List<Material>)GlobalCacheUtil.get("material");
        if(materials==null||materials.size()==0) {



            materials = (List<Material>) redisUtils.get("material");
            if (materials == null||materials.size()==0) {

                materials = getMaterials();

            }
        }

        FileHelper.writeLogFile("初始化物料-----------结束-------");

        return materials;
    }



    public List<Material> getMaterials(){
        List<Material> materials=new ArrayList<>();
        FileHelper.writeLogFile("初始化物料-----------开始-------");
        LambdaQueryWrapper<MaterialInfo> MaterialInfoWrapper = new LambdaQueryWrapper<>();
        MaterialInfoWrapper.eq(MaterialInfo::getIsdeleted,0);


        List<MaterialInfo> materiallist=materialInfoMapper.selectList(MaterialInfoWrapper);

        LambdaQueryWrapper<MaterialPurchase> materialPurchaseWrapper= new LambdaQueryWrapper<>();
        materialPurchaseWrapper.eq(MaterialPurchase::getIsdeleted,0);

        List<MaterialPurchase> MaterialPurchaselist=materialPurchaseMapper.selectList(materialPurchaseWrapper);



        LambdaQueryWrapper<Stock> StockWrapper = new LambdaQueryWrapper<>();
        StockWrapper.eq(Stock::getIsdeleted,0);

        List<Stock> Stocklist=  stockMapper.selectList(StockWrapper);

        LambdaQueryWrapper<ErpPurchaseOrder> ErpPurchaseOrderWrapper = new LambdaQueryWrapper<>();
        ErpPurchaseOrderWrapper.eq(ErpPurchaseOrder::getIsdeleted,0);

        //原材料采购订单
        List<ErpPurchaseOrder> ErpPurchaseOrderlist=  erpPurchaseOrderMapper.selectList(ErpPurchaseOrderWrapper);

        LambdaQueryWrapper<PurchaseReceipt> PurchaseReceiptWrapper = new LambdaQueryWrapper<>();
        PurchaseReceiptWrapper.eq(PurchaseReceipt::getIsdeleted,0);

        //原材料待验
        List<PurchaseReceipt> PurchaseReceiptlist=  purchaseReceiptMapper.selectList(PurchaseReceiptWrapper);

        LambdaQueryWrapper<SjzPfWhStock> SjzPfWhStockWrapper = new LambdaQueryWrapper<>();
        SjzPfWhStockWrapper.eq(SjzPfWhStock::getIsdeleted,0);

        List<SjzPfWhStock> SjzPfWhStocklists=  sjzPfWhStockMapper.selectList(SjzPfWhStockWrapper);

        for (MaterialInfo m : materiallist)
        {
            //  materiallist.forEach(m -> {
            Material material = new Material();
            material.setId(m.getId());
            material.setMaterialType(m.getMaterialType());
            material.setMaterialTypeName(m.getMaterialTypeName());
            material.setCode(m.getCode());
            material.setName(m.getName());
            material.setMaxProduction(m.getMaxProduction());
            material.setMinProduction(m.getMinProduction());

//                material.setCkeckLeadTime(m.getInspectDuration());
//                material.setPurchaseLeadTime(m.getPurchaseDuration());

            if(Stocklist!=null&&Stocklist.size()>0) {
                List<Stock> materialStocks = Stocklist.stream()
                        .filter(t -> t.getMaterialId().equals(m.getId()))
                        .collect(Collectors.toList());
                if (materialStocks != null && materialStocks.size() > 0) {
                    double stock = materialStocks.stream()
                            .filter(t -> t.getMaterialId().equals(m.getId()))
                            .mapToDouble(Stock::getTotal)
                            .sum();
                    material.setCurrentStock(stock);

                    material.setMaterialStocks(materialStocks);
                }
            }

            List<MaterialPurchase> materialPurchases=null;
            if(MaterialPurchaselist!=null&&MaterialPurchaselist.size()>0)
            {
                materialPurchases = MaterialPurchaselist.stream()
                        .filter(t -> t.getMaterialId().equals(m.getId()))
                        .collect(Collectors.toList());

                material.setMaterialPurchases(materialPurchases);
            }

            if(m.getMaterialTypeName()==null)
            {
                continue;
            }
            List<MaterialSupply> materialSupplys = new ArrayList<>();
            if (m.getMaterialTypeName().equals("MP")) {
                List<PurchaseReceipt> PurchaseReceipts = PurchaseReceiptlist.stream()
                        .filter(t -> t.getMaterialid().equals(m.getId()) )
                        .collect(Collectors.toList());
                if (PurchaseReceipts != null&&PurchaseReceipts.size()>0) {

                    for (PurchaseReceipt mm : PurchaseReceipts) {//原材料待验
                        MaterialSupply ms = new MaterialSupply();
                        LocalDateTime dt = mm.getExp5() == null ? ParamValidator.parseDateTime(mm.getExp1()+" 00:00:00", "") : mm.getExp5();
                        ms.setQuantity(mm.getFjl1Sl());
                        ms.setArrivalTime(dt);
                        materialSupplys.add(ms);
                    }

                }
                List<ErpPurchaseOrder> ErpPurchaseOrders = ErpPurchaseOrderlist.stream()
                        .filter(t -> t.getMaterialId().equals( m.getId()))
                        .collect(Collectors.toList());
                if (ErpPurchaseOrders != null&&ErpPurchaseOrders.size()>0) {
                    for (ErpPurchaseOrder mm : ErpPurchaseOrders) {//原材料采购，可用时间要加上检验时间
                        MaterialSupply ms = new MaterialSupply();
                        if(mm.getArrivalDate()==null)
                        {
                            continue;
                        }
                        int checkday=0;
                        if(materialPurchases!=null&&materialPurchases.size()>0)
                        {
                            MaterialPurchase materialPurchase=materialPurchases.stream()
                                    .filter(t->t.getSupplyId()
                                            .equals(mm.getManufacturerId()))
                                    .findFirst().orElse(null);
                            if(materialPurchase!=null)
                            {
                                checkday=materialPurchase.getInspectionCycle();
                            }
                        }

                        LocalDateTime dt = mm.getArrivalDate().plusDays(checkday);
                        ms.setQuantity(mm.getPurchaseQty());
                        ms.setArrivalTime(dt);
                        materialSupplys.add(ms);
                    }
                }
            } else {
                List<SjzPfWhStock> SjzPfWhStocks = SjzPfWhStocklists.stream()
                        .filter(t -> t.getMaterialid().equals(m.getId()) )
                        .collect(Collectors.toList());
                if (SjzPfWhStocks != null&&SjzPfWhStocks.size()>0) {
                    for (SjzPfWhStock mm : SjzPfWhStocks) {//原材料采购，可用时间要加上检验时间
                        MaterialSupply ms = new MaterialSupply();
                        LocalDateTime dt = ParamValidator.parseDateTime(mm.getExp1()+" 00:00:00", "");
                        ms.setQuantity(mm.getFjl1Sl());
                        ms.setArrivalTime(dt);
                        materialSupplys.add(ms);
                    }
                }
            }
            material.setInTransit(materialSupplys);
            materials.add(material);
            // });
        }
        redisUtils.set("material",materials);
        GlobalCacheUtil.put("material",materials, 10, TimeUnit.MINUTES);
        FileHelper.writeLogFile("初始化物料-----------结束-------");
        return  materials;
    }

    /**
     * 获取供给关系
     * @param sceneId 场景ID
     * @param entryId 工序ID
     * @param sceneService 场景服务
     * @return 供给关系列表
     */
    public List<Object> getSupplyRelation(String sceneId, Integer entryId, SceneService sceneService) {
        List<Object> supplyRelations = new ArrayList<>();
        try {

            Chromosome chromosome = sceneService.loadChromosomeFromFile(sceneId);

            if (chromosome == null || chromosome.getAllOperations() == null) return supplyRelations;
            List<Entry> entries = chromosome.getAllOperations();
            List<Order> orders = chromosome.getOrders();
            List<GAScheduleResult> results = chromosome.getResult();
            LocalDateTime baseTime = chromosome.getBaseTime();
            Entry currentEntry = entries.stream().filter(e -> e.getId() == entryId).findFirst().orElse(null);
            if (currentEntry != null) {
                // 处理DependentOnOrderIds
                if (currentEntry.getDependentOnOrderIds() != null && !currentEntry.getDependentOnOrderIds().isEmpty()) {
                    for (Integer orderId : currentEntry.getDependentOnOrderIds()) {
                        // 首先找到对应的Order对象
                        Order targetOrder;
                        if (orders != null) {
                            targetOrder = orders.stream().filter(o -> o.getId() == orderId).findFirst().orElse(null);
                        } else {
                            targetOrder = null;
                        }

                        // 如果找到了Order对象，再找到对应的Entry
                        if (targetOrder != null) {
                            // 找到该订单的所有工序
                            List<Entry> orderEntries = entries.stream()
                                    .filter(e -> e.getOrderId() != null && e.getOrderId().equals(targetOrder.getOrderId()))
                                    .collect(Collectors.toList());

                            if (!orderEntries.isEmpty()) {
                                // 找到该订单的最后一道工序（按Sequence排序）
                                Entry lastEntry = orderEntries.stream()
                                        .max(Comparator.comparingInt(Entry::getSequence))
                                        .orElse(null);

                                if (lastEntry != null) {
                                    // 找到当前工序的开始时间
                                    LocalDateTime currentStartTime = getEntryStartTime(currentEntry, results, baseTime);
                                    // 找到上一道工序的结束时间
                                    LocalDateTime lastEntryEndTime = getEntryEndTime(lastEntry, results, baseTime);

                                    Order fromOrder1 = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(lastEntry.getOrderId())).findFirst().orElse(null) : null;
                                    Order toOrder1 = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(currentEntry.getOrderId())).findFirst().orElse(null) : null;
                                    long fromEquipId1 = results.stream().filter(r -> r.getOperationId() == lastEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                                    long toEquipId1 = results.stream().filter(r -> r.getOperationId() == currentEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                                    Map<String, Object> item = new HashMap<>();
                                    item.put("fromId", String.valueOf(lastEntry.getId()));
                                    item.put("fromPlanId", fromOrder1 != null ? String.valueOf(fromOrder1.getId()) : "");
                                    item.put("fromEquipId", String.valueOf(fromEquipId1));
                                    item.put("fromTime", lastEntryEndTime != null ? lastEntryEndTime.toString() : "2025-12-13");
                                    item.put("toId", String.valueOf(currentEntry.getId()));
                                    item.put("toPlanId", toOrder1 != null ? String.valueOf(toOrder1.getId()) : "");
                                    item.put("toEquipId", String.valueOf(toEquipId1));
                                    item.put("toTime", currentStartTime != null ? currentStartTime.toString() : "2026-12-13");
                                    supplyRelations.add(item);

                                    // 递归检查上一个订单的依赖关系
                                    checkAndAddDependentRelations(entries, orders, results, baseTime, lastEntry, supplyRelations);
                                }
                            }
                        }
                    }
                }
                // 处理TargetFinishedOperationId
                Entry supplyEntry = findLastOperationInSameOrder(entries, currentEntry);
                List<Integer> targetFinishedOperationIds = getTargetFinishedOperationIds(supplyEntry, currentEntry);
                if (supplyEntry != null && targetFinishedOperationIds != null && !targetFinishedOperationIds.isEmpty()) {
                    for (Integer targetId : targetFinishedOperationIds) {
                        Entry targetEntry = entries.stream().filter(e -> e.getId() == targetId).findFirst().orElse(null);
                        if (targetEntry != null) {
                            // 找到当前工序的结束时间
                            LocalDateTime currentEndTime = getEntryEndTime(supplyEntry, results, baseTime);
                            // 找到目标工序的开始时间
                            LocalDateTime targetStartTime = getEntryStartTime(targetEntry, results, baseTime);

                            Order fromOrder2 = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(supplyEntry.getOrderId())).findFirst().orElse(null) : null;
                            Order toOrder2 = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(targetEntry.getOrderId())).findFirst().orElse(null) : null;
                            long fromEquipId2 = results.stream().filter(r -> r.getOperationId() == supplyEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                            long toEquipId2 = results.stream().filter(r -> r.getOperationId() == targetEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                            Map<String, Object> item = new HashMap<>();
                            item.put("fromId", String.valueOf(supplyEntry.getId()));
                            item.put("fromPlanId", fromOrder2 != null ? String.valueOf(fromOrder2.getId()) : "");
                            item.put("fromEquipId", String.valueOf(fromEquipId2));
                            item.put("fromTime", currentEndTime != null ? currentEndTime.toString() : "2025-12-13");
                            item.put("toId", String.valueOf(targetEntry.getId()));
                            item.put("toPlanId", toOrder2 != null ? String.valueOf(toOrder2.getId()) : "");
                            item.put("toEquipId", String.valueOf(toEquipId2));
                            item.put("toTime", targetStartTime != null ? targetStartTime.toString() : "2026-12-13");
                            supplyRelations.add(item);
                            checkAndAddTargetRelations(entries, orders, results, baseTime, targetEntry, supplyRelations); // 检查后置工序
                        }
                    }
                }

            }
        } catch (Exception e) {
            log.error("获取供给关系失败: {}", e.getMessage(), e);
        }
        return supplyRelations;
    }

    /**
     * 获取工单的开始时间
     * @param entry 工单
     * @param results 调度结果列表
     * @param baseTime 基准时间
     * @return 开始时间
     */
    private LocalDateTime getEntryStartTime(Entry entry, List<GAScheduleResult> results, LocalDateTime baseTime) {
        if (results == null || baseTime == null) return null;
        GAScheduleResult result = results.stream()
                .filter(r -> r.getOperationId() == entry.getId())
                .findFirst()
                .orElse(null);
        if (result != null) {
            return baseTime.plusSeconds(result.getStartTime());
        }
        return null;
    }

    /**
     * 获取工单的结束时间
     * @param entry 工单
     * @param results 调度结果列表
     * @param baseTime 基准时间
     * @return 结束时间
     */
    private LocalDateTime getEntryEndTime(Entry entry, List<GAScheduleResult> results, LocalDateTime baseTime) {
        if (results == null || baseTime == null) return null;
        GAScheduleResult result = results.stream()
                .filter(r -> r.getOperationId() == entry.getId())
                .findFirst()
                .orElse(null);
        if (result != null) {
            return baseTime.plusSeconds(result.getEndTime());
        }
        return null;
    }

    /**
     * 递归检查并添加依赖关系
     * @param entries 所有工序列表
     * @param orders 所有订单列表
     * @param results 调度结果列表
     * @param baseTime 基准时间
     * @param currentEntry 当前工序
     * @param supplyRelations 供给关系列表
     */
    private void checkAndAddDependentRelations(List<Entry> entries, List<Order> orders, List<GAScheduleResult> results, LocalDateTime baseTime, Entry currentEntry, List<Object> supplyRelations) {
        if (currentEntry.getDependentOnOrderIds() != null && !currentEntry.getDependentOnOrderIds().isEmpty()) {
            for (Integer orderId : currentEntry.getDependentOnOrderIds()) {
                // 首先找到对应的Order对象
                Order targetOrder;
                if (orders != null) {
                    targetOrder = orders.stream().filter(o -> o.getId() == orderId).findFirst().orElse(null);
                } else {
                    targetOrder = null;
                }

                // 如果找到了Order对象，再找到对应的Entry
                if (targetOrder != null) {
                    // 找到该订单的所有工序
                    List<Entry> orderEntries = entries.stream()
                            .filter(e -> e.getOrderId() != null && e.getOrderId().equals(targetOrder.getOrderId()))
                            .collect(Collectors.toList());

                    if (!orderEntries.isEmpty()) {
                        // 找到该订单的最后一道工序（按Sequence排序）
                        Entry lastEntry = orderEntries.stream()
                                .max(Comparator.comparingInt(Entry::getSequence))
                                .orElse(null);

                        if (lastEntry != null) {
                            // 找到当前工序的开始时间
                            LocalDateTime currentStartTime = getEntryStartTime(currentEntry, results, baseTime);
                            // 找到上一道工序的结束时间
                            LocalDateTime lastEntryEndTime = getEntryEndTime(lastEntry, results, baseTime);

                            Order fromOrder3 = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(lastEntry.getOrderId())).findFirst().orElse(null) : null;
                            Order toOrder3 = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(currentEntry.getOrderId())).findFirst().orElse(null) : null;
                            long fromEquipId3 = results.stream().filter(r -> r.getOperationId() == lastEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                            long toEquipId3 = results.stream().filter(r -> r.getOperationId() == currentEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                            Map<String, Object> item = new HashMap<>();
                            item.put("fromId", String.valueOf(lastEntry.getId()));
                            item.put("fromPlanId", fromOrder3 != null ? String.valueOf(fromOrder3.getId()) : "");
                            item.put("fromEquipId", String.valueOf(fromEquipId3));
                            item.put("fromTime", lastEntryEndTime != null ? lastEntryEndTime.toString() : "2025-12-13");
                            item.put("toId", String.valueOf(currentEntry.getId()));
                            item.put("toPlanId", toOrder3 != null ? String.valueOf(toOrder3.getId()) : "");
                            item.put("toEquipId", String.valueOf(toEquipId3));
                            item.put("toTime", currentStartTime != null ? currentStartTime.toString() : "2026-12-13");
                            supplyRelations.add(item);

                            // 递归调用，处理上一个订单的最后一道工序的依赖关系
                            checkAndAddDependentRelations(entries, orders, results, baseTime, lastEntry, supplyRelations);
                        }
                    }
                }
            }
        }
    }

    /**
     * 递归检查并添加目标关系
     * @param entries 所有工序列表
     * @param results 调度结果列表
     * @param baseTime 基准时间
     * @param currentEntry 当前工序
     * @param supplyRelations 供给关系列表
     */
    private void checkAndAddTargetRelations(List<Entry> entries, List<Order> orders, List<GAScheduleResult> results, LocalDateTime baseTime, Entry currentEntry, List<Object> supplyRelations) {
        Entry supplyEntry = findLastOperationInSameOrder(entries, currentEntry);
        List<Integer> targetFinishedOperationIds = getTargetFinishedOperationIds(supplyEntry, currentEntry);
        if (supplyEntry == null || targetFinishedOperationIds == null || targetFinishedOperationIds.isEmpty()) {
            return;
        }
        for (Integer targetId : targetFinishedOperationIds) {
                Entry targetEntry = entries.stream().filter(e -> e.getId() == targetId).findFirst().orElse(null);
                if (targetEntry != null) {
                    // 找到当前工序的结束时间
                    LocalDateTime currentEndTime = getEntryEndTime(supplyEntry, results, baseTime);
                    // 找到目标工序的开始时间
                    LocalDateTime targetStartTime = getEntryStartTime(targetEntry, results, baseTime);
                    Order fromOrder = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(supplyEntry.getOrderId())).findFirst().orElse(null) : null;
                    Order toOrder = orders != null ? orders.stream().filter(o -> o.getOrderId() != null && o.getOrderId().equals(targetEntry.getOrderId())).findFirst().orElse(null) : null;
                    long fromEquipId4 = results.stream().filter(r -> r.getOperationId() == supplyEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                    long toEquipId4 = results.stream().filter(r -> r.getOperationId() == targetEntry.getId()).mapToLong(r -> r.getMachineId()).findFirst().orElse(-1L);
                    Map<String, Object> item = new HashMap<>();
                    item.put("fromId", String.valueOf(supplyEntry.getId()));
                    item.put("fromPlanId", fromOrder != null ? String.valueOf(fromOrder.getId()) : "");
                    item.put("fromEquipId", String.valueOf(fromEquipId4));
                    item.put("fromTime", currentEndTime != null ? currentEndTime.toString() : "2025-12-13");
                    item.put("toId", String.valueOf(targetEntry.getId()));
                    item.put("toPlanId", toOrder != null ? String.valueOf(toOrder.getId()) : "");
                    item.put("toEquipId", String.valueOf(toEquipId4));
                    item.put("toTime", targetStartTime != null ? targetStartTime.toString() : "2026-12-13");
                    supplyRelations.add(item);
                    checkAndAddTargetRelations(entries, orders, results, baseTime, targetEntry, supplyRelations); // 递归调用
                }
        }
    }

    private Entry findLastOperationInSameOrder(List<Entry> entries, Entry entry) {
        if (entry == null || entries == null) {
            return null;
        }
        Entry lastEntry = entries.stream()
                .filter(e -> e.getOrderId() != null && e.getOrderId().equals(entry.getOrderId()))
                .max(Comparator.comparingInt(Entry::getSequence))
                .orElse(null);
        if (lastEntry != null) {
            return lastEntry;
        }
        return entries.stream()
                .filter(e -> e.getGroupId() == entry.getGroupId())
                .max(Comparator.comparingInt(Entry::getSequence))
                .orElse(entry);
    }

    private List<Integer> getTargetFinishedOperationIds(Entry sourceEntry, Entry fallbackEntry) {
        if (sourceEntry != null
                && sourceEntry.getTargetFinishedOperationId() != null
                && !sourceEntry.getTargetFinishedOperationId().isEmpty()) {
            return sourceEntry.getTargetFinishedOperationId();
        }
        return fallbackEntry != null ? fallbackEntry.getTargetFinishedOperationId() : null;
    }
    private Map<Integer, Object> InitEntrys(String SceneId,List<ProdEquipment> ProdEquipments,List<Order> ProdLaunchOrders)
    {
        FileHelper.writeLogFile("初始化工单-----------开始-------");
        Map<Integer, Object> entrys=  _routingDataService.InitEntrys(SceneId,ProdEquipments,ProdLaunchOrders);
        FileHelper.writeLogFile("初始化工单-----------结束-------");
        return entrys;
    }

    private void InitRouting(String SceneId,List<Order> ProdLaunchOrders)
    {
        FileHelper.writeLogFile("初始化工艺-----------开始-------");

        FileHelper.writeLogFile("初始化工艺-----------结束-------");
    }



    public GenVO convertGeneToGenVO(Gene gene, LocalDateTime baseTime) {
        GenVO genVO = new GenVO();
        genVO.setOrderId(String.valueOf(gene.getOrderId()));
        genVO.setOperationId(gene.getOperationId());
        genVO.setEquipId(gene.getMachineId());
        genVO.setQuantity(BigDecimal.valueOf(gene.getBatchSize()));
        genVO.setStartTime(baseTime.plusMinutes(gene.getStartTime()));
        genVO.setEndTime(baseTime.plusMinutes(gene.getEndTime()));
        genVO.setOperationName(""); // 从其他数据源获取
        genVO.setEquipName(""); // 从其他数据源获取
        return genVO;
    }

    // 批量转换
    public List<GenVO> convertGeneListToGenVO(List<Gene> geneList, LocalDateTime baseTime) {
        return geneList.stream()
                .map(gene -> convertGeneToGenVO(gene, baseTime))
                .collect(Collectors.toList());
    }

    public List<MachineVO> convertMachineListToVO(List<Machine> machines) {
        return machines.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    private MachineVO convertToVO(Machine machine) {
        MachineVO machineVO = new MachineVO();
        machineVO.setId(machine.getId());
        machineVO.setEquipId(String.valueOf(machine.getId()));
        machineVO.setEquipName(machine.getName());
        machineVO.setCapacityTypeName(machine.getCapacityTypeName());
        // 注意：tasks 字段需要在其他地方设置，因为 Machine 类中没有任务信息
        return machineVO;
    }





    public List<Machine> InitCalendarToAllMachines1(String SceneId) {
        // 按设备分组
        List<ProdEquipment> ProdEquipments=  _prodEquipmentService.lambdaQuery()
                .eq(ProdEquipment::getSceneId,SceneId)
                .list();
        List<Long> MachineIds = ProdEquipments.stream()
                .map(ProdEquipment::getEquipId)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        List<Machine> machines=new ArrayList<>();

        for (Long id : MachineIds) {
            Machine machine=new Machine();
            machine.setId(id);
            machines.add(machine);
        }
        //节假日
        List<MesHoliday> holidays=  _MesHolidayService.list();

        LambdaQueryWrapper<ProdEquipSpecialCal> ProdEquipSpecialCalWrapper = new LambdaQueryWrapper<>();
        ProdEquipSpecialCalWrapper.eq(ProdEquipSpecialCal::getSceneId, SceneId);

        List<PlanResource> PlanResources=  _PlanResourceService.lambdaQuery()
                .eq(PlanResource::getIsdeleted,0)
                .list();



        List<ProdEquipSpecialCal> ProdEquipSpecialCals=  _prodEquipSpecialCalService.list(ProdEquipSpecialCalWrapper);

        List<MesShiftWorkSched> MesShiftWorkScheds=  _MesShiftWorkSchedService.lambdaQuery()
                .eq(MesShiftWorkSched::getIsdeleted,0).list();


        if (machines == null) {
            return null;
        }

        for (Machine machine : machines) {
            // 确保维护窗口列表不为null
            if (machine.getMaintenanceWindows() == null) {
                machine.setMaintenanceWindows(new ArrayList<>());
            }
            List<ProdEquipSpecialCal> machineProdEquipSpecialCals = ProdEquipSpecialCals.stream()
                    .filter(t -> t.getPlanResourceId()== machine.getId()&&t.getReferenceType()==1)
                    .collect(Collectors.toList());
            List<Shift> shifts1=new ArrayList<>();
            for (ProdEquipSpecialCal machineProdEquipSpecialCal : machineProdEquipSpecialCals) {

                List<MesShiftWorkSched> ShiftWorkScheds = MesShiftWorkScheds.stream()
                        .filter(t -> (long) t.getWeekWorkSchedId() == machineProdEquipSpecialCal.getReferenceId())
                        .collect(Collectors.toList());
                List<Shift> Shifts = mergeShiftDataToEng(ShiftWorkScheds);
                for (Shift shift : Shifts) {

                    shift.setMachineId(machine.getId());
                    shift.setSpecial(true);
                    shift.setStartDate(machineProdEquipSpecialCal.getStartDate());
                    shift.setEndDate(machineProdEquipSpecialCal.getEndDate());
                    shifts1.add(shift);
                }
            }


            List<PlanResource> PlanResources1 = PlanResources.stream()
                    .filter(t -> t.getReferenceId() == machine.getId())
                    .collect(Collectors.toList());
            if(PlanResources1!=null&&PlanResources1.size()>0)
            {
                for (PlanResource PlanResource : PlanResources1) {

                    List<MesShiftWorkSched> ShiftWorkScheds = MesShiftWorkScheds.stream()
                            .filter(t -> (long) t.getWeekWorkSchedId() == PlanResource.getWorkSchedId())
                            .collect(Collectors.toList());
                    List<Shift> Shifts = mergeShiftDataToEng(ShiftWorkScheds);
                    for (Shift shift : Shifts) {
                        shift.setSpecial(false);
                        shift.setMachineId(machine.getId());
//                        shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
//                        shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
                        shifts1.add(shift);
                    }
                }

            }



            // 转换为列表返回
            List<Shift> result = new ArrayList<>();
            for (Shift shift : shifts1) {
                // 处理跨天班次（开始时间晚于结束时间的情况，如 7:30 到 3:30）
                if (shift.getEndTime().isBefore(shift.getStartTime())) {
                    // 创建第一天的班次 (开始时间到24:00)
                    Shift firstShift = new Shift();
                    firstShift.setStartTime(shift.getStartTime());
                    firstShift.setEndTime(LocalTime.of(23, 59, 59)); // 23:59:59代替24:00
                    firstShift.setDays(new HashSet<>(shift.getDays()));
                    firstShift.setStatus(shift.getStatus());
                    firstShift.setStartDate(shift.getStartDate());
                    firstShift.setEndDate(shift.getEndDate());
                    firstShift.setSpecial(shift.isSpecial());
                    // 创建第二天的班次 (00:00到结束时间)
                    Shift secondShift = new Shift();
                    secondShift.setStartTime(LocalTime.MIDNIGHT);
                    secondShift.setEndTime(shift.getEndTime());
                    secondShift.setDays(new HashSet<>(shift.getDays()));
                    secondShift.setStatus(shift.getStatus());
                    secondShift.setStartDate(shift.getStartDate().plusDays(1));
                    secondShift.setEndDate(shift.getEndDate().plusDays(1));
                    secondShift.setSpecial(shift.isSpecial());
                    result.add(firstShift);
                    result.add(secondShift);
                } else {
                    // 正常班次直接添加
                    result.add(shift);
                }
            }
            machine.setShifts(result);


            List<ProdEquipSpecialCal> Holidays = ProdEquipSpecialCals.stream()
                    .filter(t -> t.getEquipId() == machine.getId()&&t.getReferenceType()==2)
                    .collect(Collectors.toList());
            List<Holiday> Holidays1=new ArrayList<>();
            for (ProdEquipSpecialCal machineProdEquipSpecialCal : Holidays) {

                Holiday holiday=new Holiday();
                holiday.setStart(machineProdEquipSpecialCal.getStartDate());
                holiday.setEnd(machineProdEquipSpecialCal.getEndDate());
                Holidays1.add(holiday);
            }
            machine.setHolidays(Holidays1);



        }
        applySceneCapacityTypeName(machines, ProdEquipments);
        return  machines;


    }
    /**
     * 合并重复的ShiftData，将serialNumber收集为列表
     * @param originalList 原始数据列表
     * @return 合并后的MergedShiftData列表
     */
    public static List<Shift> mergeShiftData(List<MesShiftWorkSched> originalList) {
        // 按shiftStart和shiftEnd分组
        Map<String, Shift> groupMap = new HashMap<>();

        for (MesShiftWorkSched data : originalList) {
            // 用shiftStart+shiftEnd作为分组key
            String groupKey = data.getShiftStart().toString() + "_" + data.getShiftEnd().toString();

            if (groupMap.containsKey(groupKey)) {
                // 已存在分组：添加serialNumber到列表
                Shift merged = groupMap.get(groupKey);
                merged.getDays().add(data.getStartWeekDay());
            } else {
                // 新分组：创建MergedShiftData并初始化
                Shift merged = new Shift();

                merged.setStartTime(data.getShiftStart().toLocalTime());
                merged.setEndTime(data.getShiftEnd().toLocalTime());
                merged.setStatus(0);

                // 初始化序号列表
                Set<Integer> serials =new HashSet<>();
                serials.add(data.getStartWeekDay());
                merged.setDays(serials);
                groupMap.put(groupKey, merged);
            }
        }

        // 转换为列表返回
        return new ArrayList<>(groupMap.values());
    }




    /**
     * 合并重复的ShiftData，将serialNumber收集为列表英文格式0,1,2,3,4,5,6
     * @param originalList 原始数据列表
     * @return 合并后的MergedShiftData列表
     */
    public static List<Shift> mergeShiftDataToEng(List<MesShiftWorkSched> originalList) {
        // 按shiftStart和shiftEnd分组
        Map<String, Shift> groupMap = new HashMap<>();

        for (MesShiftWorkSched data : originalList) {
            // 用shiftStart+shiftEnd作为分组key
            String groupKey = data.getShiftStart().toString() + "_" + data.getShiftEnd().toString();

            // 将中文的星期几转换为英文格式（周日是0，周一到周日依次为0-6）
            // 假设数据库中startWeekDay是1-7（周一到周日），需要转换为0-6（周日到周六）
            int engDay = (data.getStartWeekDay() % 7); // 将1-7转换为0-6，其中周日为0

            if (groupMap.containsKey(groupKey)) {
                // 已存在分组：添加serialNumber到列表
                Shift merged = groupMap.get(groupKey);
                merged.getDays().add(engDay);
            } else {
                // 新分组：创建MergedShiftData并初始化
                Shift merged = new Shift();

                merged.setStartTime(data.getShiftStart().toLocalTime());
                merged.setEndTime(data.getShiftEnd().toLocalTime());
                merged.setStatus(0);

                // 初始化序号列表
                Set<Integer> serials =new HashSet<>();
                serials.add(engDay);
                merged.setDays(serials);
                groupMap.put(groupKey, merged);
            }
        }

        // 转换为列表返回
        return new ArrayList<>(groupMap.values());
    }




    /**
     * 将 ScheduleChromosome 转换为 ResourceGanttVO 列表
     * @param scheduleChromosome 调度结果
     * @param machineList 机器列表
     * @return 转换后的数据
     */
    public List<ResourceGanttVO> convertToResourceGanttVO1(Chromosome scheduleChromosome, List<Machine> machineList) {
        List<ResourceGanttVO> resourceGanttVOList = new ArrayList<>();


        List<Entry> allOperations = scheduleChromosome.getAllOperations();
        // 遍历所有机器资源
        if (machineList != null) {
            for (int i = 0; i < machineList.size(); i++) {
                Machine machine = machineList.get(i);

                ResourceGanttVO resourceGanttVO = new ResourceGanttVO();
                resourceGanttVO.setId(machine.getId());
                resourceGanttVO.setName(machine.getName());
                resourceGanttVO.setShift(convertToShiftVO(machine));
                resourceGanttVO.setCode(machine.getCode());
                // 转换任务列表
                List<TaskVO> taskVOList = new ArrayList<>();
                if (scheduleChromosome.getResult() != null) {
                    // 筛选出属于当前设备的任务
                    List<GAScheduleResult> machineGenes = scheduleChromosome.getResult().stream()
                            .filter(gene -> gene.getMachineId()==(machine.getId()))
                            .collect(Collectors.toList());
                    // 按开始时间排序
                    machineGenes.sort((g1, g2) -> Integer.compare(g1.getStartTime(), g2.getStartTime()));

                    for (GAScheduleResult gene : machineGenes) {

                        Entry entry = allOperations.stream()
                                .filter(t -> t.getId() == gene.getOperationId()).findFirst().orElse(null);


                        TaskVO taskVO = new TaskVO();
                        taskVO.setId(String.valueOf(gene.getOperationId()));
                        taskVO.setPlanId(gene.getOrderId()); // 默认值
                        taskVO.setPlanCode(gene.getOrderCode()); // 默认值
//                        taskVO.setProductType(0); // 默认值
                        taskVO.setProductName(gene.getProductName());
                        taskVO.setProductId(gene.getProductId()); // 默认值
                        taskVO.setProductCode(gene.getProductCode()); // 默认值
                        taskVO.setQuantity(gene.getQuantity());
                        taskVO.setStart(scheduleChromosome.getBaseTime().plusSeconds(gene.getStartTime()));
                        taskVO.setEnd(scheduleChromosome.getBaseTime().plusSeconds(gene.getEndTime()));
                        taskVO.setSetup(gene.getPreTime());
                        taskVO.setTeardown(gene.getTeardownTime()); // 默认值
                        taskVO.setEquipChange(gene.getChangeOverTime()); // 默认值
                        taskVO.setEquipCooling(0); // 默认值
                        taskVO.setEquipType(resourceGanttVO.getType());
                        taskVO.setEquipName(resourceGanttVO.getName());
                        taskVO.setLocked(gene.isIsLocked()); // 设置锁定状态

                        // 处理锁定期工单（entry为null的情况）
                        if (entry != null) {
                            taskVO.setSeq(Math.toIntExact(entry.getTaskSeq()));
                            taskVO.setSeqName(entry.getRoutingDetailName());
                            taskVO.setDetailId(entry.getRoutingDetailId());
                            taskVO.setHeaderId(entry.getRoutingId());
                            taskVO.setHeaderName(entry.getRoutingName());
                        } else {
                            // 锁定期工单使用 gene 中的信息
                            taskVO.setSeq(gene.getSeq());
                            taskVO.setSeqName("锁定期工序");
                            taskVO.setDetailId(0L);
                            taskVO.setHeaderId(0);
                            taskVO.setHeaderName("锁定期工单");
                        }

                        if (gene.getDesignatedStartTime()>0) {
                            taskVO.setDesignatedStartTime(scheduleChromosome.getBaseTime().plusSeconds(gene.getDesignatedStartTime()));
                        }else {

                            taskVO.setDesignatedStartTime(null);

                        }
//                        taskVO.setDuration(calculateDuration(
//                                scheduleChromosome.getBaseTime().plusMinutes(gene.getStartTime()),
//                                scheduleChromosome.getBaseTime().plusMinutes(gene.getEndTime()))); // 计算持续时间

                        taskVO.setDuration(0); //
                        taskVO.setEquipId(machine.getId());
                        taskVO.setShopId(machine.getId());
                        taskVO.setShopName(resourceGanttVO.getShopName());
                        taskVO.setStatus(0); // 默认值
                        taskVO.setProcessingTime(gene.getProcessingTime());

                        taskVOList.add(taskVO);

                        taskVO.setAbsolutePreparationTime(gene.getTeardownTime());



                    }
                }

                resourceGanttVO.setList(taskVOList);
                resourceGanttVOList.add(resourceGanttVO);
            }
        }

        return resourceGanttVOList;
    }

    /**
     * 将 ScheduleChromosome 转换为 ProductGanttVO 列表
     * @param scheduleChromosome 调度结果
     * @return 转换后的数据
     */
    public List<com.aps.entity.Gantt.ProductGanttVO> convertToProductGanttVO1(Chromosome scheduleChromosome) {
        List<com.aps.entity.Gantt.ProductGanttVO> productGanttVOList = new ArrayList<>();
        List<Entry> allOperations = scheduleChromosome.getAllOperations();

        // 按产品ID和工单ID分组基因
        if (scheduleChromosome.getResult() != null) {
            // 按工单ID分组（过滤掉 OrderId 为 null 的记录）
            scheduleChromosome.getResult().stream()
                    .filter(r -> r.getOrderId() != null && !r.getOrderId().isEmpty())
                    .collect(Collectors.groupingBy(GAScheduleResult::getOrderId))
                    .forEach((orderId, genes) -> {
                        if (!genes.isEmpty()) {
                            com.aps.entity.Gantt.ProductGanttVO productGanttVO = new com.aps.entity.Gantt.ProductGanttVO();
                            GAScheduleResult firstGene = genes.get(0);
                            productGanttVO.setId(firstGene.getOrderId());
                            productGanttVO.setProductName(firstGene.getProductName());
                            productGanttVO.setProductType(0);
                            productGanttVO.setProductId(firstGene.getProductId());
                            // 计算总数量（假设同一批次）
                            productGanttVO.setQuantity(firstGene.getQuantity());
                            productGanttVO.setCode(firstGene.getProductCode());
//                            productGanttVO.setShopId(firstGene.getMachineId());
//                            productGanttVO.setShopName(firstGene.getMachineId()+"号线");
                            productGanttVO.setStatus("已发布");
                            productGanttVO.setOrderCode(firstGene.getOrderCode());
                            Entry entry = allOperations.stream()
                                    .filter(t -> t.getId() == firstGene.getOperationId()).findFirst().orElse(null);
                            if (entry != null) {
                                productGanttVO.setHeaderId(entry.getRoutingId());
                                productGanttVO.setHeaderName(entry.getRoutingName());
                            }

                            // 计算开始和结束时间
                            int minStartTime = genes.stream()
                                    .mapToInt(GAScheduleResult::getStartTime)
                                    .min()
                                    .orElse(0);
                            int maxEndTime = genes.stream()
                                    .mapToInt(GAScheduleResult::getEndTime)
                                    .max()
                                    .orElse(0);

                            productGanttVO.setStartDate(scheduleChromosome.getBaseTime().plusSeconds(minStartTime));
                            productGanttVO.setEndDate(scheduleChromosome.getBaseTime().plusSeconds(maxEndTime));

                            // 转换任务列表
                            List<TaskVO> taskVOList = new ArrayList<>();
//                            // 按工序顺序排序
//                            genes.sort((g1, g2) -> Integer.compare(g1.getSequenceId(), g2.getSequenceId()));

                            for (int i = 0; i < genes.size(); i++) {
                                GAScheduleResult gene = genes.get(i);

                                Entry entry1 = allOperations.stream()
                                        .filter(t -> t.getId() == gene.getOperationId()).findFirst().orElse(null);

                                TaskVO taskVO = new TaskVO();
                                taskVO.setId(String.valueOf(gene.getOperationId()));
                                taskVO.setPlanId(gene.getOrderId());
                                taskVO.setPlanCode(gene.getOrderCode());
                                taskVO.setProductName(gene.getProductName());
                                taskVO.setProductId(gene.getProductId());
                                taskVO.setProductCode(gene.getProductCode());
                                taskVO.setQuantity(gene.getQuantity());
                                taskVO.setStart(scheduleChromosome.getBaseTime().plusSeconds(gene.getStartTime()));
                                taskVO.setEnd(scheduleChromosome.getBaseTime().plusSeconds(gene.getEndTime()));
                                taskVO.setSetup(gene.getPreTime());
                                taskVO.setTeardown(gene.getTeardownTime());
                                taskVO.setEquipChange(gene.getChangeOverTime());
                                taskVO.setEquipCooling(0);
                                taskVO.setLocked(gene.isIsLocked());

                                if (entry1 != null) {
                                    taskVO.setSeq(Math.toIntExact(entry1.getTaskSeq()));
                                    taskVO.setSeqName(entry1.getRoutingDetailName());
                                }

                                if (gene.getDesignatedStartTime()>0) {
                                    taskVO.setDesignatedStartTime(scheduleChromosome.getBaseTime().plusSeconds(gene.getDesignatedStartTime()));
                                } else {
                                    taskVO.setDesignatedStartTime(null);
                                }

                                taskVO.setDuration(0);
                                taskVO.setEquipId(gene.getMachineId());
                                taskVO.setShopId(gene.getMachineId());
                                taskVO.setShopName(gene.getMachineId()+"车间");
                                taskVO.setStatus(0);

                                if (entry1 != null) {
                                    taskVO.setDetailId(entry1.getRoutingDetailId());
                                    taskVO.setHeaderId(entry1.getRoutingId());
                                    taskVO.setHeaderName(entry1.getRoutingName());
                                }

                                taskVO.setProcessingTime(gene.getProcessingTime());
                                taskVO.setAbsolutePreparationTime(gene.getTeardownTime());

                                taskVOList.add(taskVO);
                            }

                            productGanttVO.setList(taskVOList);
                            productGanttVOList.add(productGanttVO);
                        }
                    });
        }

        return productGanttVOList;
    }




    private ShiftVO convertToShiftVO(Machine machine) {
        ShiftVO shiftVO= new ShiftVO();
        shiftVO.setId(machine.getId());
        shiftVO.setName(machine.getName());
        shiftVO.setShifts(machine.getShifts());
        shiftVO.setMaintenanceWindows(machine.getMaintenanceWindows());
        // 注意：tasks 字段需要在其他地方设置，因为 Machine 类中没有任务信息
        return shiftVO;
    }


    /**
     * 计算任务持续时间（分钟）
     * @param start 开始时间
     * @param end 结束时间
     * @return 持续时间（分钟）
     */
    private Integer calculateDuration(LocalDateTime start, LocalDateTime end) {
        if (start == null || end == null) {
            return 0;
        }
        return Math.toIntExact(java.time.Duration.between(start, end).toMinutes());
    }


    public List<Machine> InitCalendarToAllMachines2(String SceneId) {


        Chromosome chromosome = _sceneService.loadChromosomeFromFile(SceneId);
        GlobalParam globalParam = (chromosome != null && chromosome.getGlobalParamSnapshot() != null)
                ? chromosome.getGlobalParamSnapshot().copy()
                : InitGlobalParam();
        boolean IsUseCalendar = globalParam.isIsUseCalendar();

        // 按设备分组
        List<ProdEquipment> ProdEquipments=  _prodEquipmentService.lambdaQuery()
                .eq(ProdEquipment::getSceneId,SceneId)
                .list();
        Set<Long> machineIdSet = ProdEquipments.stream()
                .map(ProdEquipment::getEquipId)
                .collect(Collectors.toSet());

        // 添加锁定期工单使用的设备ID
        try {
            ApsTimeConfig timeConfig = apsTimeConfigService.getOne(new LambdaQueryWrapper<>());
            if (timeConfig != null && timeConfig.getBaseTime() != null && timeConfig.getFreezeDate() != null) {
                LocalDateTime baseTime = timeConfig.getBaseTime();
                long freezeSeconds = timeConfig.getFreezeDate().longValue();

                if (freezeSeconds > 0) {
                    // 锁定期计算：baseTime 到 baseTime + freezeSeconds
                    LocalDateTime lockStartTime = baseTime;
                    LocalDateTime lockEndTime = baseTime.plusSeconds(freezeSeconds);

                    // 查询锁定期内的工单使用的设备ID
                    List<Dispatch> frozenDispatches = dispatchService.lambdaQuery()
                            .ge(Dispatch::getBeginTime, lockStartTime)
                            .le(Dispatch::getBeginTime, lockEndTime)
                            .eq(Dispatch::getIsDeleted, 0L)
                            .isNotNull(Dispatch::getEquipId)
                            .list();

                    // 提取设备ID并添加到Set中
                    for (Dispatch dispatch : frozenDispatches) {
                        if (dispatch.getEquipId() != null) {
                            machineIdSet.add(dispatch.getEquipId());
                        }
                    }

                    log.info("锁定期工单使用的所有设备ID: {}", machineIdSet);
                }
            }
        } catch (Exception e) {
            log.error("加载锁定期设备ID时发生错误: {}", e.getMessage(), e);
        }

        // 转换为排序后的List
        List<Long> MachineIds = machineIdSet.stream()
                .sorted()
                .collect(Collectors.toList());



        List<Machine> machines = new ArrayList<>();
        List<PlanResource> PlanResources = _PlanResourceService.lambdaQuery()
                .eq(PlanResource::getIsdeleted, 0)
                .list();

        //维修记录
        LambdaQueryWrapper<EquipMaintainTask> EquipMaintainTaskWrapper = new LambdaQueryWrapper<>();
        EquipMaintainTaskWrapper.eq(EquipMaintainTask::getIsdeleted, 0);
        EquipMaintainTaskWrapper.eq(EquipMaintainTask::getStatus, 0);
        EquipMaintainTaskWrapper.ge(EquipMaintainTask::getPlanFinishTime, baseTime);
        List<EquipMaintainTask> EquipMaintainTasks = _equipMaintainTaskService.list(EquipMaintainTaskWrapper);

        for (Long id : MachineIds) {
            Machine machine = new Machine();
            PlanResource planResource = PlanResources.stream()
                    .filter(t -> t.getId() == id.intValue())
                    .findFirst().orElse(null);


            List<MaintenanceWindow> maintenanceWindows=new ArrayList<>();
            if (planResource != null){
                machine.setCode(planResource.getReferenceCode());
                machine.setName(planResource.getTitle());
                machine.setDepartment(planResource.getDepartTitle());
                List<EquipMaintainTask> EquipMaintainTasks1 = EquipMaintainTasks.stream()
                        .filter(t -> t.getEquipId().equals(planResource.getReferenceId()) )
                        .collect(Collectors.toList());
                for (EquipMaintainTask equipMaintainTask : EquipMaintainTasks1) {
                    MaintenanceWindow maintenanceWindow=new MaintenanceWindow();
                    maintenanceWindow.setId(UUID.randomUUID().toString());
                    maintenanceWindow.setStartTime(equipMaintainTask.getPlanStartTime());
                    maintenanceWindow.setEndTime(equipMaintainTask.getPlanFinishTime());
                    maintenanceWindow.setReason("");
                    maintenanceWindow.setEquipCode(equipMaintainTask.getEquipCode());
                    maintenanceWindow.setEquipName(equipMaintainTask.getEquipName());
                    maintenanceWindows.add(maintenanceWindow);
                }

                machine.setMaintenanceWindows(maintenanceWindows);



            }
            machine.setId(id);
            machines.add(machine);
        }
        //节假日
        //  List<MesHoliday> holidays=  _MesHolidayService.list();
        if (IsUseCalendar) {
            LambdaQueryWrapper<ProdEquipSpecialCal> ProdEquipSpecialCalWrapper = new LambdaQueryWrapper<>();
            ProdEquipSpecialCalWrapper.eq(ProdEquipSpecialCal::getSceneId, SceneId);


            List<ProdEquipSpecialCal> ProdEquipSpecialCals = _prodEquipSpecialCalService.list(ProdEquipSpecialCalWrapper);

            List<MesShiftWorkSched> MesShiftWorkScheds = _MesShiftWorkSchedService.lambdaQuery()
                    .eq(MesShiftWorkSched::getIsdeleted, 0).list();


            if (machines == null) {
                return null;
            }

            for (Machine machine : machines) {
                // 确保维护窗口列表不为null
                if (machine.getMaintenanceWindows() == null) {
                    machine.setMaintenanceWindows(new ArrayList<>());
                }
                List<ProdEquipSpecialCal> machineProdEquipSpecialCals = ProdEquipSpecialCals.stream()
                        .filter(t -> t.getPlanResourceId() != null && t.getPlanResourceId() == machine.getId() && t.getReferenceType() == 1)
                        .collect(Collectors.toList());
                List<Shift> shifts1 = new ArrayList<>();
                for (ProdEquipSpecialCal machineProdEquipSpecialCal : machineProdEquipSpecialCals) {

                    List<MesShiftWorkSched> ShiftWorkScheds = MesShiftWorkScheds.stream()
                            .filter(t -> (long) t.getWeekWorkSchedId() == machineProdEquipSpecialCal.getReferenceId())
                            .collect(Collectors.toList());
                    List<Shift> Shifts = mergeShiftData(ShiftWorkScheds);
                    for (Shift shift : Shifts) {

                        shift.setMachineId(machine.getId());
                        shift.setStartDate(machineProdEquipSpecialCal.getStartDate());
                        shift.setEndDate(machineProdEquipSpecialCal.getEndDate());
                        shifts1.add(shift);
                        shift.setSpecial(true);
                    }
                }
                PlanResource PlanResource = PlanResources.stream()
                        .filter(t -> t.getId() == machine.getId())
                        .findFirst().orElse(null);
                if (PlanResource != null) {
                    machine.setCode(PlanResource.getReferenceCode());
                    machine.setName(PlanResource.getTitle());
                    machine.setDepartment(PlanResource.getDepartTitle());
                    List<MesShiftWorkSched> ShiftWorkScheds = MesShiftWorkScheds.stream()
                            .filter(t -> (long) t.getWeekWorkSchedId() == PlanResource.getWorkSchedId())
                            .collect(Collectors.toList());
                    List<Shift> Shifts = mergeShiftData(ShiftWorkScheds);
                    for (Shift shift : Shifts) {

                        shift.setMachineId(machine.getId());
                        shift.setSpecial(false);
                        shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
                        shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
                        shifts1.add(shift);
                    }


                }
                if (shifts1 == null || shifts1.size() == 0) {
                    throw new RuntimeException(String.format("设备%s没有工作日历", machine.getCode().concat("_").concat(machine.getName())));
                }

                // 转换为列表返回
                List<Shift> result = new ArrayList<>();
                for (Shift shift : shifts1) {
                    // 处理跨天班次（开始时间晚于结束时间的情况，如 7:30 到 3:30）
                    if (shift.getEndTime().isBefore(shift.getStartTime())) {
                        // 创建第一天的班次 (开始时间到24:00)
                        Shift firstShift = new Shift();
                        firstShift.setStartTime(shift.getStartTime());
                        firstShift.setEndTime(LocalTime.of(23, 59, 59)); // 23:59:59代替24:00
                        firstShift.setDays(new HashSet<>(shift.getDays()));
                        firstShift.setStatus(shift.getStatus());
                        firstShift.setStartDate(shift.getStartDate());
                        firstShift.setEndDate(shift.getEndDate());
                        firstShift.setSpecial(shift.isSpecial());
                        // 创建第二天的班次 (00:00到结束时间)
                        Shift secondShift = new Shift();
                        secondShift.setStartTime(LocalTime.MIDNIGHT);
                        secondShift.setEndTime(shift.getEndTime());
                        secondShift.setDays(new HashSet<>(shift.getDays()));
                        secondShift.setStatus(shift.getStatus());
                        secondShift.setStartDate(shift.getStartDate().plusDays(1));
                        secondShift.setEndDate(shift.getEndDate().plusDays(1));
                        secondShift.setSpecial(shift.isSpecial());
                        result.add(firstShift);
                        result.add(secondShift);
                    } else {
                        // 正常班次直接添加
                        result.add(shift);
                    }
                }

                machine.setShifts(result);

                List<ProdEquipSpecialCal> Holidays = ProdEquipSpecialCals.stream()
                        .filter(t -> t.getEquipId() == machine.getId() && t.getReferenceType() == 2)
                        .collect(Collectors.toList());
                List<Holiday> Holidays1 = new ArrayList<>();
                for (ProdEquipSpecialCal machineProdEquipSpecialCal : Holidays) {

                    Holiday holiday = new Holiday();
                    holiday.setStart(machineProdEquipSpecialCal.getStartDate());
                    holiday.setEnd(machineProdEquipSpecialCal.getEndDate());
                    Holidays1.add(holiday);
                }
                machine.setHolidays(Holidays1);


            }
        } else {
            for (Machine machine : machines) {
                List<Shift> shifts1 = new ArrayList<>();
                Shift shift=new Shift();
                shift.setMachineId(machine.getId());
                shift.setStartTime(LocalTime.of(0,0,0));
                shift.setEndTime(LocalTime.of(23,59,59));
                HashSet days= new HashSet<>();
                days.add(1);
                days.add(2);
                days.add(3);
                days.add(4);
                days.add(5);
                days.add(6);
                days.add(0);
                shift.setDays(days);
                shift.setSpecial(false);
                shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
                shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
                shifts1.add(shift);
                machine.setShifts(shifts1);
            }
        }
        applySceneCapacityTypeName(machines, ProdEquipments);
        return machines;


    }





    public List<Machine> InitCalendarToAllMachines3(Chromosome chromosome)  {

        List<Machine> machines = chromosome.getInitMachines();

        // 如果initMachines为空，返回空列表
        if (machines == null || machines.isEmpty()) {
            return new ArrayList<>();
        }

        Set<Long> machineIds = chromosome.getResult().stream()
                .map(GAScheduleResult::getMachineId)
                .collect(Collectors.toSet());

        machines = machines.stream()
                .filter(machine -> machineIds.contains(machine.getId()))
                .collect(Collectors.toList());
        for (Machine machine:machines) {
            {
                List<Shift> result = new ArrayList<>();
                List<Shift> shifts = machine.getShifts();
                if (shifts != null) {
                    for (Shift shift : shifts) {
                        // 处理跨天班次（开始时间晚于结束时间的情况，如 7:30 到 3:30）
                        if (shift.getEndTime().isBefore(shift.getStartTime())) {
                            // 创建第一天的班次 (开始时间到24:00)
                            Shift firstShift = new Shift();
                            firstShift.setStartTime(shift.getStartTime());
                            firstShift.setEndTime(LocalTime.of(23, 59, 59)); // 23:59:59代替24:00
                            firstShift.setDays(new HashSet<>(shift.getDays()));
                            firstShift.setStatus(shift.getStatus());
                            firstShift.setStartDate(shift.getStartDate());
                            firstShift.setEndDate(shift.getEndDate());
                            firstShift.setSpecial(shift.isSpecial());
                            // 创建第二天的班次 (00:00到结束时间)
                            Shift secondShift = new Shift();
                            secondShift.setStartTime(LocalTime.MIDNIGHT);
                            secondShift.setEndTime(shift.getEndTime());
                            secondShift.setDays(new HashSet<>(shift.getDays()));
                            secondShift.setStatus(shift.getStatus());
                            secondShift.setStartDate(shift.getStartDate().plusDays(1));
                            secondShift.setEndDate(shift.getEndDate().plusDays(1));
                            secondShift.setSpecial(shift.isSpecial());
                            result.add(firstShift);
                            result.add(secondShift);
                        } else {
                            // 正常班次直接添加
                            result.add(shift);
                        }
                    }
                }

                machine.setShifts(result);
            }
        }

        return machines;


    }

    /**
     * 获取指定场景ID的文件数字
     * @param sceneId 场景ID
     * @return 包含文件名后数字的列表
     */
    public List<Integer> getSceneFileNumbers(String sceneId) {
        List<Integer> numbers = new ArrayList<>();
        SceneChromsome sceneChromsome=(SceneChromsome)redisUtils.get("SceneId."+sceneId);
        if (sceneChromsome==null){
            return numbers;
        }

        Integer   currultVersion =sceneChromsome.getVersion();


        // 获取结果目录
        File resultDir = new File("result");
        if (!resultDir.exists() || !resultDir.isDirectory()) {
            return numbers;
        }

        // 获取目录中的所有文件
        File[] files = resultDir.listFiles();
        if (files == null) {
            return numbers;
        }

        // 定义要查找的前缀
        String prefix = "chromosome_result_" + sceneId + "_";
        String suffix = "_.json";

        for (File file : files) {
            if (file.isFile()) {
                String fileName = file.getName();

                // 检查文件名是否以指定前缀开始，并以指定后缀结束
                if (fileName.startsWith(prefix) && fileName.endsWith(suffix)) {
                    // 提取前缀和后缀之间的部分
                    String middlePart = fileName.substring(
                            prefix.length(),
                            fileName.length() - suffix.length()
                    );

                    // 尝试将中间部分解析为数字
                    try {
                        int number = Integer.parseInt(middlePart);
                        // 只添加小于当前版本的数字
                        if (number < currultVersion) {
                            numbers.add(number);
                        }
                    } catch (NumberFormatException e) {
                        // 如果中间部分不是数字，则跳过该文件
                        continue;
                    }
                }
            }
        }

        // 对数字列表进行排序（从小到大）
        Collections.sort(numbers);
        return numbers;
    }


    public Map<String, Object> getSceneVersion(String sceneId) {
        List<Integer> numbers = new ArrayList<>();
        SceneChromsome sceneChromsome=(SceneChromsome)redisUtils.get("SceneId."+sceneId);
        if (sceneChromsome==null){
            Map<String, Object> result = new HashMap<>();
            result.put("list", numbers);
            result.put("index", -1);
            return result;
        }

        Integer   currultVersion =sceneChromsome.getVersion();


        // 获取结果目录
        File resultDir = new File("result");
        if (!resultDir.exists() || !resultDir.isDirectory()) {
            Map<String, Object> result = new HashMap<>();
            result.put("list", numbers);
            result.put("index", -1);
            return result;
        }

        // 获取目录中的所有文件
        File[] files = resultDir.listFiles();
        if (files == null) {
            Map<String, Object> result = new HashMap<>();
            result.put("list", numbers);
            result.put("index", -1);

            return result;
        }

        // 定义要查找的前缀
        String prefix = "chromosome_result_" + sceneId + "_";
        String suffix = "_.json";

        for (File file : files) {
            if (file.isFile()) {
                String fileName = file.getName();

                // 检查文件名是否以指定前缀开始，并以指定后缀结束
                if (fileName.startsWith(prefix) && fileName.endsWith(suffix)) {
                    // 提取前缀和后缀之间的部分
                    String middlePart = fileName.substring(
                            prefix.length(),
                            fileName.length() - suffix.length()
                    );

                    // 尝试将中间部分解析为数字
                    try {
                        int number = Integer.parseInt(middlePart);

                        numbers.add(number);

                    } catch (NumberFormatException e) {
                        // 如果中间部分不是数字，则跳过该文件
                        continue;
                    }
                }
            }
        }

        // 对数字列表进行排序（从小到大）
        Collections.sort(numbers);

        // 查找当前版本在numbers中的索引
        int index = numbers.indexOf(currultVersion);
        if (index == -1 && !numbers.isEmpty()) {
            // 如果当前版本不在历史版本列表中，返回列表长度作为位置
            index = numbers.size();
        } else if (numbers.isEmpty()) {
            index = -1; // 如果列表为空，索引为-1
        }

        Map<String, Object> result = new HashMap<>();
        result.put("list", numbers);
        result.put("index", index);

        return result;
    }



    public Map<String, Object> getSceneVersionWithIndexPreview(String sceneId, Map<String, Object> params) {
        Map<String, Object> versionData = getSceneVersion(sceneId);
        SceneVersionPreviewData previewData = collectSceneVersionPreviewData(sceneId);
        if (previewData == null) {
            throw new RuntimeException("未找到对应的场景文件: " + getCurrentChromosomeFileName(sceneId));
        }

        int previewWidth = getPositiveIntegerParam(params, "previewWidth", 100);
        int previewHeight = getPositiveIntegerParam(params, "previewHeight", calculateDefaultPreviewHeight(previewData.equipCount));
        return buildSceneVersionPreview(versionData, previewData, previewWidth, previewHeight);
    }

    private Map<String, Object> buildSceneVersionPreview(Map<String, Object> versionData,
                                                         SceneVersionPreviewData previewData,
                                                         int previewWidth,
                                                         int previewHeight) {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("index", versionData == null ? -1 : versionData.get("index"));
        result.put("start", formatApiTimestamp(previewData.minStart));
        result.put("end", formatApiTimestamp(previewData.maxEnd));
        result.put("taskCount", previewData.taskCount);
        result.put("planCount", previewData.planCount);
        result.put("equipCount", previewData.equipCount);
        result.put("taskMinTime", previewData.taskMinTime);
        result.put("taskMaxTime", previewData.taskMaxTime);
        result.put("taskAverageTime", previewData.taskAverageTime);
        result.put("previewWidth", previewWidth);
        result.put("previewHeight", previewHeight);
        result.put("preview", buildGanttPreviewPng(previewData, previewWidth, previewHeight));
        result.put("list", versionData == null ? new ArrayList<>() : versionData.get("list"));
        return result;
    }

    private String formatApiTimestamp(LocalDateTime time) {
        return time == null ? null : time.format(API_TIMESTAMP_FORMATTER);
    }

    private String getCurrentChromosomeFileName(String sceneId) {
        try {
            File file = _sceneService.getCurrentChromosomeFile(sceneId);
            return file == null ? sceneId : file.getName();
        } catch (RuntimeException ex) {
            log.warn("获取场景文件名失败，sceneId={}", sceneId, ex);
            return sceneId;
        }
    }

    private SceneVersionPreviewData collectSceneVersionPreviewData(String sceneId) {
        File file = _sceneService.getCurrentChromosomeFile(sceneId);
        if (file == null || !file.exists() || file.length() == 0L) {
            log.warn("场景缩略图文件不存在或为空: {}", file == null ? sceneId : file.getAbsolutePath());
            return null;
        }

        String cacheKey = file.getAbsolutePath() + "|" + file.length() + "|" + file.lastModified();
        SceneVersionPreviewData cached = previewDataCache.get(cacheKey);
        if (cached != null) {
            return cached;
        }

        long start = System.nanoTime();
        try {
            SceneVersionPreviewData previewData = parseSceneVersionPreviewData(file);
            previewDataCache.put(cacheKey, previewData);
            long elapsedMs = (System.nanoTime() - start) / 1_000_000;
            log.info("场景数据加载, sceneId={}, fileSize={} bytes, elapsed={} ms",
                    sceneId, file.length(), elapsedMs);
            return previewData;
        } catch (IOException ex) {
            log.warn("场景数据加载, sceneId={}, file={}", sceneId, file.getAbsolutePath(), ex);
            Chromosome schedule = _sceneService.loadChromosomeFromFile(sceneId);
            return schedule == null ? null : collectSceneVersionPreviewData(schedule);
        }
    }

    private SceneVersionPreviewData parseSceneVersionPreviewData(File file) throws IOException {
        SceneVersionPreviewData previewData = new SceneVersionPreviewData();
        try (JsonParser parser = previewJsonFactory.createParser(file)) {
            if (parser.nextToken() != JsonToken.START_OBJECT) {
                return previewData;
            }
            JsonToken token;
            while ((token = parser.nextToken()) != null && token != JsonToken.END_OBJECT) {
                if (token != JsonToken.FIELD_NAME) {
                    parser.skipChildren();
                    continue;
                }
                String fieldName = parser.currentName();
                JsonToken valueToken = parser.nextToken();
                if ("baseTime".equals(fieldName) || "BaseTime".equals(fieldName)) {
                    readPreviewBaseTime(parser, previewData);
                } else if ("initMachines".equals(fieldName) || "InitMachines".equals(fieldName)) {
                    readPreviewMachines(parser, previewData);
                } else if ("result".equals(fieldName) || "Result".equals(fieldName)) {
                    readPreviewResult(parser, previewData);
                } else if (valueToken == JsonToken.START_OBJECT || valueToken == JsonToken.START_ARRAY) {
                    parser.skipChildren();
                }
            }
        }
        finishPreviewData(previewData);
        return previewData;
    }

    private void readPreviewBaseTime(JsonParser parser, SceneVersionPreviewData previewData) throws IOException {
        if (parser.currentToken() != JsonToken.VALUE_STRING) {
            parser.skipChildren();
            return;
        }
        String value = parser.getValueAsString();
        if (value == null || value.trim().isEmpty()) {
            return;
        }
        try {
            previewData.baseTime = LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        } catch (RuntimeException ex) {
            log.warn("Failed to parse scene preview baseTime: {}", value, ex);
        }
    }

    private void readPreviewMachines(JsonParser parser, SceneVersionPreviewData previewData) throws IOException {
        if (parser.currentToken() != JsonToken.START_ARRAY) {
            parser.skipChildren();
            return;
        }
        JsonToken token;
        while ((token = parser.nextToken()) != null && token != JsonToken.END_ARRAY) {
            if (token != JsonToken.START_OBJECT) {
                parser.skipChildren();
                continue;
            }
            Long machineId = null;
            while ((token = parser.nextToken()) != null && token != JsonToken.END_OBJECT) {
                if (token != JsonToken.FIELD_NAME) {
                    parser.skipChildren();
                    continue;
                }
                String fieldName = parser.currentName();
                JsonToken valueToken = parser.nextToken();
                if ("id".equals(fieldName)) {
                    machineId = parser.getValueAsLong();
                } else if (valueToken == JsonToken.START_OBJECT || valueToken == JsonToken.START_ARRAY) {
                    parser.skipChildren();
                }
            }
            if (machineId != null && !previewData.genesByMachine.containsKey(machineId)) {
                previewData.machineIds.add(machineId);
                previewData.genesByMachine.put(machineId, new ArrayList<>());
            }
        }
    }

    private void readPreviewResult(JsonParser parser, SceneVersionPreviewData previewData) throws IOException {
        if (parser.currentToken() != JsonToken.START_ARRAY) {
            parser.skipChildren();
            return;
        }
        JsonToken token;
        while ((token = parser.nextToken()) != null && token != JsonToken.END_ARRAY) {
            if (token != JsonToken.START_OBJECT) {
                parser.skipChildren();
                continue;
            }
            GAScheduleResult gene = new GAScheduleResult();
            boolean hasMachineId = false;
            boolean hasStartTime = false;
            boolean hasEndTime = false;
            while ((token = parser.nextToken()) != null && token != JsonToken.END_OBJECT) {
                if (token != JsonToken.FIELD_NAME) {
                    parser.skipChildren();
                    continue;
                }
                String fieldName = parser.currentName();
                JsonToken valueToken = parser.nextToken();
                if ("machineId".equals(fieldName) || "MachineId".equals(fieldName)) {
                    gene.setMachineId(parser.getValueAsLong());
                    hasMachineId = true;
                } else if ("startTime".equals(fieldName) || "StartTime".equals(fieldName)) {
                    gene.setStartTime(parser.getValueAsInt());
                    hasStartTime = true;
                } else if ("endTime".equals(fieldName) || "EndTime".equals(fieldName)) {
                    gene.setEndTime(parser.getValueAsInt());
                    hasEndTime = true;
                } else if ("orderId".equals(fieldName) || "OrderId".equals(fieldName)) {
                    gene.setOrderId(parser.getValueAsString());
                } else if ("orderCode".equals(fieldName) || "OrderCode".equals(fieldName)) {
                    gene.setOrderCode(parser.getValueAsString());
                } else if ("operationId".equals(fieldName) || "OperationId".equals(fieldName)) {
                    gene.setOperationId(parser.getValueAsInt());
                } else if (valueToken == JsonToken.START_OBJECT || valueToken == JsonToken.START_ARRAY) {
                    parser.skipChildren();
                }
            }
            if (hasMachineId && hasStartTime && hasEndTime) {
                previewData.pendingGenes.add(gene);
            }
        }
    }

    private void finishPreviewData(SceneVersionPreviewData previewData) {
        if (previewData.genesByMachine.isEmpty() || previewData.pendingGenes.isEmpty()) {
            return;
        }

        Long minStartOffset = null;
        Long maxEndOffset = null;
        long durationSum = 0L;
        int durationCount = 0;
        Set<String> planIds = new HashSet<>();

        for (GAScheduleResult gene : previewData.pendingGenes) {
            List<GAScheduleResult> machineGenes = previewData.genesByMachine.get(gene.getMachineId());
            if (machineGenes == null) {
                continue;
            }
            machineGenes.add(gene);
            previewData.taskCount++;
            planIds.add(getSchedulePlanKey(gene));

            long startOffset = gene.getStartTime();
            long endOffset = gene.getEndTime();
            minStartOffset = minStartOffset == null ? startOffset : Math.min(minStartOffset, startOffset);
            maxEndOffset = maxEndOffset == null ? endOffset : Math.max(maxEndOffset, endOffset);

            long duration = endOffset - startOffset;
            if (duration >= 0L) {
                previewData.taskMinTime = durationCount == 0 ? duration : Math.min(previewData.taskMinTime, duration);
                previewData.taskMaxTime = durationCount == 0 ? duration : Math.max(previewData.taskMaxTime, duration);
                durationSum += duration;
                durationCount++;
            }
        }

        Iterator<Long> machineIterator = previewData.machineIds.iterator();
        while (machineIterator.hasNext()) {
            Long machineId = machineIterator.next();
            List<GAScheduleResult> machineGenes = previewData.genesByMachine.get(machineId);
            if (machineGenes == null || machineGenes.isEmpty()) {
                machineIterator.remove();
                previewData.genesByMachine.remove(machineId);
            } else {
                machineGenes.sort(Comparator.comparingInt(GAScheduleResult::getStartTime));
            }
        }

        previewData.planCount = planIds.size();
        previewData.equipCount = previewData.machineIds.size();
        previewData.taskAverageTime = durationCount == 0 ? 0L : Math.round(durationSum / (double) durationCount);
        previewData.minStartOffset = minStartOffset;
        previewData.maxEndOffset = maxEndOffset;
        if (previewData.baseTime != null && minStartOffset != null && maxEndOffset != null) {
            previewData.minStart = previewData.baseTime.plusSeconds(minStartOffset);
            previewData.maxEnd = previewData.baseTime.plusSeconds(maxEndOffset);
        }
        previewData.pendingGenes.clear();
    }

    private SceneVersionPreviewData collectSceneVersionPreviewData(Chromosome schedule) {
        SceneVersionPreviewData previewData = new SceneVersionPreviewData();
        if (schedule == null || schedule.getResult() == null || schedule.getResult().isEmpty()) {
            return previewData;
        }

        List<GAScheduleResult> genes = schedule.getResult();
        Set<Long> resultMachineIds = new HashSet<>();
        for (GAScheduleResult gene : genes) {
            if (gene != null) {
                resultMachineIds.add(gene.getMachineId());
            }
        }

        List<Machine> machines = schedule.getInitMachines();
        if (machines == null || machines.isEmpty()) {
            return previewData;
        }

        for (Machine machine : machines) {
            if (machine == null || !resultMachineIds.contains(machine.getId())) {
                continue;
            }
            previewData.machineIds.add(machine.getId());
            previewData.genesByMachine.put(machine.getId(), new ArrayList<>());
        }
        previewData.equipCount = previewData.machineIds.size();
        if (previewData.equipCount == 0) {
            return previewData;
        }

        Long minStartOffset = null;
        Long maxEndOffset = null;
        long durationSum = 0L;
        int durationCount = 0;
        Set<String> planIds = new HashSet<>();

        for (GAScheduleResult gene : genes) {
            if (gene == null || !previewData.genesByMachine.containsKey(gene.getMachineId())) {
                continue;
            }

            previewData.genesByMachine.get(gene.getMachineId()).add(gene);
            previewData.taskCount++;
            planIds.add(getSchedulePlanKey(gene));

            long startOffset = gene.getStartTime();
            long endOffset = gene.getEndTime();
            minStartOffset = minStartOffset == null ? startOffset : Math.min(minStartOffset, startOffset);
            maxEndOffset = maxEndOffset == null ? endOffset : Math.max(maxEndOffset, endOffset);

            long duration = endOffset - startOffset;
            if (duration >= 0L) {
                previewData.taskMinTime = durationCount == 0 ? duration : Math.min(previewData.taskMinTime, duration);
                previewData.taskMaxTime = durationCount == 0 ? duration : Math.max(previewData.taskMaxTime, duration);
                durationSum += duration;
                durationCount++;
            }
        }

        for (List<GAScheduleResult> machineGenes : previewData.genesByMachine.values()) {
            machineGenes.sort(Comparator.comparingInt(GAScheduleResult::getStartTime));
        }

        previewData.planCount = planIds.size();
        previewData.taskAverageTime = durationCount == 0 ? 0L : Math.round(durationSum / (double) durationCount);
        previewData.minStartOffset = minStartOffset;
        previewData.maxEndOffset = maxEndOffset;
        if (schedule.getBaseTime() != null && minStartOffset != null && maxEndOffset != null) {
            previewData.minStart = schedule.getBaseTime().plusSeconds(minStartOffset);
            previewData.maxEnd = schedule.getBaseTime().plusSeconds(maxEndOffset);
        }

        return previewData;
    }

    private int getPositiveIntegerParam(Map<String, Object> params, String key, int defaultValue) {
        if (params == null || params.get(key) == null) {
            return defaultValue;
        }
        try {
            int value = Integer.parseInt(String.valueOf(params.get(key)));
            return value > 0 ? value : defaultValue;
        } catch (NumberFormatException ex) {
            return defaultValue;
        }
    }

    private int calculateDefaultPreviewHeight(int equipCount) {
        return Math.max(160, Math.min(1200, equipCount * 6));
    }

    private String buildGanttPreviewPng(SceneVersionPreviewData previewData,
                                        int imageWidth,
                                        int imageHeight) {
        if (previewData == null || previewData.machineIds.isEmpty() || previewData.minStartOffset == null
                || previewData.maxEndOffset == null || previewData.maxEndOffset <= previewData.minStartOffset) {
            return "";
        }

        long totalSeconds = Math.max(1L, previewData.maxEndOffset - previewData.minStartOffset);
        int equipCount = previewData.machineIds.size();
        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = image.createGraphics();
        Map<String, Color> colorCache = new HashMap<>();

        try {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
            graphics.setColor(new Color(0xf6f8fb));
            graphics.fillRect(0, 0, imageWidth, imageHeight);

            for (int i = 0; i < previewData.machineIds.size(); i++) {
                List<GAScheduleResult> machineGenes = previewData.genesByMachine.get(previewData.machineIds.get(i));
                if (machineGenes == null || machineGenes.isEmpty()) {
                    continue;
                }
                double y = getPreviewRowY(i, equipCount, imageHeight);
                double rowHeight = getPreviewRowHeight(i, equipCount, imageHeight, y);
                for (GAScheduleResult gene : machineGenes) {
                    long duration = gene.getEndTime() - gene.getStartTime();
                    if (duration < 0L) {
                        continue;
                    }
                    long offset = Math.max(0L, gene.getStartTime() - previewData.minStartOffset);
                    double x = offset * (double) imageWidth / totalSeconds;
                    double width = Math.max(1D, Math.max(1L, duration) * (double) imageWidth / totalSeconds);
                    if (x >= imageWidth || x + width <= 0) {
                        continue;
                    }
                    if (x < 0) {
                        width += x;
                        x = 0;
                    }
                    width = Math.min(width, imageWidth - x);
                    if (width <= 0 || rowHeight <= 0) {
                        continue;
                    }
                    fillPreviewRect(graphics, x, y, width, rowHeight,
                            getScheduleTaskColor(gene, colorCache), imageWidth, imageHeight);
                }
            }
        } finally {
            graphics.dispose();
        }

        try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
            ImageIO.write(image, "png", output);
            return "data:image/png;base64," + Base64.getEncoder().encodeToString(output.toByteArray());
        } catch (IOException ex) {
            log.warn("Failed to build Gantt preview PNG.", ex);
            return "";
        }
    }

    private void fillPreviewRect(Graphics2D graphics,
                                 double x,
                                 double y,
                                 double width,
                                 double height,
                                 Color color,
                                 int imageWidth,
                                 int imageHeight) {
        int left = Math.max(0, (int) Math.floor(x));
        int top = Math.max(0, (int) Math.floor(y));
        int right = Math.min(imageWidth, Math.max(left + 1, (int) Math.ceil(x + width)));
        int bottom = Math.min(imageHeight, Math.max(top + 1, (int) Math.ceil(y + height)));
        if (left >= imageWidth || top >= imageHeight || right <= left || bottom <= top) {
            return;
        }

        graphics.setColor(color);
        graphics.fillRect(left, top, right - left, bottom - top);
    }

    private double getPreviewRowY(int index, int equipCount, int imageHeight) {
        if (equipCount <= 0 || imageHeight <= 0) {
            return 0D;
        }
        if (imageHeight < equipCount) {
            return Math.min(imageHeight - 1D, Math.floor(index * (double) imageHeight / equipCount));
        }
        return index * (double) imageHeight / equipCount;
    }

    private double getPreviewRowHeight(int index, int equipCount, int imageHeight, double y) {
        if (equipCount <= 0 || imageHeight <= 0 || y >= imageHeight) {
            return 0D;
        }
        if (imageHeight < equipCount) {
            double nextY = Math.floor((index + 1D) * imageHeight / equipCount);
            return Math.min(imageHeight - y, Math.max(1D, nextY - y));
        }
        double rowHeight = imageHeight / (double) equipCount;
        return Math.min(rowHeight, Math.max(1D, rowHeight * 0.85D));
    }

    private Color getScheduleTaskColor(GAScheduleResult gene, Map<String, Color> colorCache) {
        String key = getSchedulePlanKey(gene);
        Color color = colorCache.get(key);
        if (color != null) {
            return color;
        }
        int hue = key == null ? 210 : (key.hashCode() & 0x7fffffff) % 360;
        Color rgb = hslToRgb(hue, 0.70D, 0.55D);
        color = new Color(rgb.getRed(), rgb.getGreen(), rgb.getBlue(), 199);
        colorCache.put(key, color);
        return color;
    }

    private String getSchedulePlanKey(GAScheduleResult gene) {
        if (gene == null) {
            return null;
        }
        if (gene.getOrderId() != null && !gene.getOrderId().trim().isEmpty()) {
            return gene.getOrderId();
        }
        if (gene.getOrderCode() != null && !gene.getOrderCode().trim().isEmpty()) {
            return gene.getOrderCode();
        }
        return String.valueOf(gene.getOperationId());
    }

    private Color hslToRgb(int hue, double saturation, double lightness) {
        double c = (1D - Math.abs(2D * lightness - 1D)) * saturation;
        double h = hue / 60D;
        double x = c * (1D - Math.abs(h % 2D - 1D));
        double r = 0D;
        double g = 0D;
        double b = 0D;

        if (h < 1D) {
            r = c;
            g = x;
        } else if (h < 2D) {
            r = x;
            g = c;
        } else if (h < 3D) {
            g = c;
            b = x;
        } else if (h < 4D) {
            g = x;
            b = c;
        } else if (h < 5D) {
            r = x;
            b = c;
        } else {
            r = c;
            b = x;
        }

        double m = lightness - c / 2D;
        return new Color(toRgbChannel(r + m), toRgbChannel(g + m), toRgbChannel(b + m));
    }

    private int toRgbChannel(double value) {
        return Math.max(0, Math.min(255, (int) Math.round(value * 255D)));
    }

    private static class SceneVersionPreviewData {
        private final List<Long> machineIds = new ArrayList<>();
        private final Map<Long, List<GAScheduleResult>> genesByMachine = new LinkedHashMap<>();
        private final List<GAScheduleResult> pendingGenes = new ArrayList<>();
        private LocalDateTime baseTime;
        private LocalDateTime minStart;
        private LocalDateTime maxEnd;
        private Long minStartOffset;
        private Long maxEndOffset;
        private int taskCount;
        private int planCount;
        private int equipCount;
        private long taskMinTime;
        private long taskMaxTime;
        private long taskAverageTime;
    }
}

