package com.aps.service.plan;



import com.aps.common.util.FileHelper;
import com.aps.entity.basic.*;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

public class AlgorithmScheduler7 {
    private final List<Product> _products;
    private final List<Machine> _machines;
    private final List<Order> _orders;
    private final Random _random;
    private final MachineSchedulerService _machineScheduler;
    private int _populationSize = 100;
    private double _crossoverRate = 0.8;
    private double _mutationRate = 0.1;
    private int _maxGenerations = 500;
    private int _elitismCount = 5;
    private final LocalDateTime baseTime = LocalDateTime.of(2025, 10, 1, 0, 0, 0);

    public AlgorithmScheduler7(List<Product> products, List<Machine> machines, List<Order> orders, MachineSchedulerService machineScheduler) {
        this._products = deepCopyProductList(products);
        this._machines = deepCopyMachineList(machines);
        this._orders = deepCopyOrderList(orders);
        this._machineScheduler = machineScheduler;
        this._random = new Random();
    }

    public ScheduleChromosome Run() {
        List<ScheduleChromosome> population = InitializePopulation();
        ScheduleChromosome bestSolution = null;
        ScheduleChromosome currentBest = null;
        double bestFitness = Double.MIN_VALUE;

        currentBest = population.stream()
                .max(Comparator.comparingDouble(ScheduleChromosome::getFitness))
                .orElse(null);

        if (currentBest != null) {
            bestFitness = currentBest.getFitness();
            bestSolution = deepCopyScheduleChromosome(currentBest);
        }

        return bestSolution;
    }

    public List<ScheduleChromosome> RunAll() {
        return InitializePopulation();
    }

    private List<ScheduleChromosome> InitializePopulation() {
        List<ScheduleChromosome> population = new ArrayList<>();

        System.out.println("开始初始化种群，目标大小: " + _populationSize);

        for (int i = 0; i < _populationSize; i++) {
            ScheduleChromosome chromosome = new ScheduleChromosome(baseTime);
            chromosome.setGenes(new ArrayList<>());
            chromosome.setObjectiveValues(new HashMap<>());
            chromosome.setOrders(deepCopyOrderList(_orders));
            chromosome.setMachines(deepCopyMachineList(_machines));

            // 为每个订单分配工序
            for (Order order : _orders) {
                Product product = _products.stream()
                        .filter(p -> p.getId() == order.getProductId())
                        .findFirst()
                        .orElseThrow(() -> new NoSuchElementException("Product not found: " + order.getProductId()));

                int prevtime = 0;
                int remainingQuantity = order.getQuantity();

                // 订单拆分逻辑 - 增强随机性
                while (remainingQuantity > 0) {
                    int batchSize;
                    if (order.isCanSplit() && remainingQuantity > 1) {
                        // 修改：增强批次拆分的随机性
                        int maxSplit = Math.min(remainingQuantity, Math.max(1, remainingQuantity / 2));
                        batchSize = _random.nextInt(maxSplit) + 1;
                    } else {
                        batchSize = remainingQuantity;
                    }
                    if (batchSize > remainingQuantity) {
                        batchSize = remainingQuantity;
                    }
                    remainingQuantity -= batchSize;

                    // 按工序顺序处理
                    for (Operation operation : product.getOperations().stream()
                            .sorted(Comparator.comparingInt(Operation::getSequence))
                            .collect(Collectors.toList())) {

                        if (operation.getId() > 1) {
                            Gene prevGene = chromosome.getGenes().stream()
                                    .filter(t -> t.getOrderId() == order.getId() && t.getOperationId() == operation.getId() - 1)
                                    .findFirst()
                                    .orElse(null);
                            prevtime = prevGene != null ? prevGene.getEndTime() : 0;
                        }

                        MachineOption machineOption;
                        Machine machine;

                        // 多设备选择逻辑 - 增强随机性
                        if (operation.getMachineOptions().size() > 1) {
                            Set<Integer> machineIds = operation.getMachineOptions().stream()
                                    .map(MachineOption::getMachineId)
                                    .collect(Collectors.toSet());

                            // 修改：增强设备选择的随机性
                            List<Machine> availableMachines = chromosome.getMachines().stream()
                                    .filter(t -> machineIds.contains(t.getId()))
                                    .collect(Collectors.toList());

                            if (!availableMachines.isEmpty()) {
                                // 随机打乱后选择
                                Collections.shuffle(availableMachines, _random);
                                machine = availableMachines.get(0);

                                Machine finalMachine = machine;
                                machineOption = operation.getMachineOptions().stream()
                                        .filter(t -> t.getMachineId() == finalMachine.getId())
                                        .findFirst()
                                        .orElseThrow(() -> new NoSuchElementException("MachineOption not found for machine: " + finalMachine.getId()));
                            } else {
                                // 回退到原始逻辑
                                machine = chromosome.getMachines().stream()
                                        .filter(t -> machineIds.contains(t.getId()))
                                        .sorted(Comparator.comparingInt(Machine::getEarliestTime)
                                                .thenComparingInt(Machine::getTotalTaskTime)
                                                .thenComparing(t -> _random.nextDouble()))
                                        .findFirst()
                                        .orElseThrow(() -> new NoSuchElementException("No available machine for operation: " + operation.getId()));

                                Machine finalMachine = machine;
                                machineOption = operation.getMachineOptions().stream()
                                        .filter(t -> t.getMachineId() == finalMachine.getId())
                                        .findFirst()
                                        .orElseThrow(() -> new NoSuchElementException("MachineOption not found for machine: " + finalMachine.getId()));
                            }
                        } else {
                            machineOption = operation.getMachineOptions().get(0);
                            MachineOption finalMachineOption = machineOption;
                            machine = chromosome.getMachines().stream()
                                    .filter(m -> m.getId() == finalMachineOption.getMachineId())
                                    .findFirst()
                                    .orElseThrow(() -> new NoSuchElementException("Machine not found: " + finalMachineOption.getMachineId()));
                        }
// ==================== 修正的时间计算逻辑开始 ====================
                        int processingTime = machineOption.getProcessingTime() * batchSize;
                        if (machineOption.getContantTime() > 0) {
                            processingTime = machineOption.getContantTime();
                        }
                        int preTime = machineOption.getPreTime();
                        int teardownTime = machineOption.getTeardownTime();
                        int setupTime = calculateSetupTime(chromosome.getGenes(), order, machine, machineOption);


                        int effectivePrepTime = Math.max(machineOption.getPreTime(), calculateSetupTime(chromosome.getGenes(), order, machine, machineOption));

// 检查是否是设备上的第一个产品
                        boolean isFirstProductOnMachine = chromosome.getGenes().stream()
                                .filter(g -> g.getMachineId() == machine.getId())
                                .noneMatch(g -> g.getProductId() == order.getProductId());

// 计算调整后的开始时间（使用有效准备时间）
                        int adjustedPrevTime = calculateAdjustedStartTime(
                                chromosome.getGenes(), order.getId(), operation.getId(),
                                effectivePrepTime, prevtime, machine.getId(), isFirstProductOnMachine
                        );

// 关键修改2：总处理时间 = 有效准备时间（最大值） + 加工时间 + 后处理时间
                        int totalProcessingDuration = effectivePrepTime + processingTime + teardownTime;

// 关键修改3：调整提议的开始时间，基于有效准备时间提前
                        int proposedStartTimeWithPreTime = adjustedPrevTime;
                        if (operation.getId() > 1 && effectivePrepTime > 0) {  // 使用有效准备时间判断
                            // 对于第二道及后续工序，有效准备时间可以提前
                            Gene lastGeneOnMachine = chromosome.getGenes().stream()
                                    .filter(g -> g.getMachineId() == machine.getId())
                                    .max(Comparator.comparingInt(Gene::getEndTime))
                                    .orElse(null);
                            int machineEarliestTime = lastGeneOnMachine != null ? lastGeneOnMachine.getEndTime() : 0;

                            // 提前量基于有效准备时间计算
                            proposedStartTimeWithPreTime = Math.max(adjustedPrevTime - effectivePrepTime, machineEarliestTime);
                        }

// 查找可用时间槽（基于有效准备时间的总时长）
                        List<GeneDetail> geneDetails = GetNextAvailableTime(
                                machine, proposedStartTimeWithPreTime, -1, totalProcessingDuration,
                                chromosome.getGenes(), false, true
                        );

                        int startTime = geneDetails.stream().mapToInt(GeneDetail::getStartTime).min().orElse(0);
                        int endTime = geneDetails.stream().mapToInt(GeneDetail::getEndTime).max().orElse(0);

// 验证有效准备时间是否被正确安排
                        if (operation.getId() > 1 && effectivePrepTime > 0) {  // 使用有效准备时间判断
                            Gene prevOperationGene = chromosome.getGenes().stream()
                                    .filter(g -> g.getOrderId() == order.getId() && g.getOperationId() == operation.getId() - 1)
                                    .findFirst()
                                    .orElse(null);

                            if (prevOperationGene != null && startTime < prevOperationGene.getEndTime()) {
                                // 调整提前量，基于有效准备时间
                                int actualStartTime = Math.max(startTime, prevOperationGene.getEndTime() - effectivePrepTime);

                                if (actualStartTime != startTime) {
                                    geneDetails = GetNextAvailableTime(
                                            machine, actualStartTime, -1, totalProcessingDuration,
                                            chromosome.getGenes(), false, true
                                    );
                                    startTime = geneDetails.stream().mapToInt(GeneDetail::getStartTime).min().orElse(0);
                                    endTime = geneDetails.stream().mapToInt(GeneDetail::getEndTime).max().orElse(0);
                                }
                            }
                        }
// ==================== 修正的时间计算逻辑结束 ====================

                        machine.setEarliestTime(endTime);
                        machine.setTotalTaskTime(machine.getTotalTaskTime() +
                                processingTime + effectivePrepTime + teardownTime );

                        Gene gene = new Gene();
                        gene.setOrderId(order.getId());
                        gene.setProductId(order.getProductId());
                        gene.setOperationId(operation.getId());
                        gene.setMachineId(machineOption.getMachineId());
                        gene.setBatchSize(batchSize);
                        gene.setStartTime(startTime); // 包含前处理的开始时间
                        gene.setEndTime(endTime);           // 包含后处理的结束时间
                        gene.setProcessingTime(processingTime);
                        gene.setPreTime(preTime);
                        gene.setSetupTime(setupTime);
                        gene.setTeardownTime(teardownTime);
                        gene.setOperationName("工序" + operation.getId());
                        gene.setGeneDetails((geneDetails));
                        gene.setId(chromosome.getGenes().size() + 1);
                        gene.setSequenceId(operation.getSequence());
                        chromosome.getGenes().add(gene);

                        int absolutePreparationTime = calculateAbsolutePreparationTime(gene, machineOption);
                        int absoluteSetupTime    =calculateAbsoluteSetupTime(gene, machineOption);
                        gene.setAbsolutePreparationTime(absolutePreparationTime);
                        int absoluteStartTime =startTime+Math.max(absolutePreparationTime,absoluteSetupTime);
                        int absoluteTeardownTime = calculateAbsoluteTeardownTime(gene, machineOption);
                        int absoluteEndTime = endTime-absoluteTeardownTime;

                        gene.setAbsoluteStartTime(absoluteStartTime);
                        gene.setAbsoluteEndTime(absoluteEndTime);
                        gene.setAbsoluteTeardownTime(absoluteTeardownTime);
                        // 更新prevtime为当前工序的结束时间
                        prevtime = endTime;
                    }
                }
            }

            population.add(chromosome);


        }

        System.out.println("生成种群大小: " + population.size());

        Map<String, List<ScheduleChromosome>> grouped = population.stream()
                .collect(Collectors.groupingBy(ScheduleChromosome::getGenesStr));

        population = grouped.values().stream()
                .map(group -> group.get(0))
                .collect(Collectors.toList());

        // 调试输出染色体多样性
        System.out.println("染色体多样性分析:");
        Map<String, Integer> keyCounts = new HashMap<>();
        for (ScheduleChromosome chrom : population) {
            String key = chrom.getGenesStr();
            keyCounts.put(key, keyCounts.getOrDefault(key, 0) + 1);
        }
        System.out.println("唯一染色体数量: " + keyCounts.size());

        // 并行计算适应度
        population.parallelStream().forEach(this::CalculateFitness);

        // 打印摘要
        population.forEach(this::WriteScheduleSummary);

        return population;
    }




    private int calculateSetupTime(List<Gene> existingGenes, Order currentOrder, Machine machine, MachineOption machineOption) {
        // 查找设备上最新的任务（按结束时间排序）
        Gene lastGeneOnMachine = existingGenes.stream()
                .filter(g -> g.getMachineId() == machine.getId())
                .max(Comparator.comparingInt(Gene::getEndTime))
                .orElse(null);

        // 无历史任务 → 换型时间0
        if (lastGeneOnMachine == null) {
//            System.out.printf("设备%d：无历史任务，换型时间=0%n", machine.getId());
            return 0;
        }

        // 产品不同 → 返回换型时间；产品相同 → 0
        int setupTime = (lastGeneOnMachine.getProductId() != currentOrder.getProductId())
                ? machineOption.getSetupTime()
                : 0;

//        System.out.printf("设备%d：上一产品ID=%d，当前产品ID=%d，换型时间=%d分钟%n",
//                machine.getId(), lastGeneOnMachine.getProductId(), currentOrder.getProductId(), setupTime);
        return setupTime;
    }

    /**
     * 计算调整后的开始时间，考虑前处理时间的重叠
     */
    private int calculateAdjustedStartTime(List<Gene> existingGenes, int orderId,
                                           int operationId, int preTime, int prevTime,
                                           int machineId, boolean isFirstProductOnMachine) {
        if (preTime <= 0 || operationId == 1) {
            return prevTime; // 第一道工序或没有前处理时间，不提前
        }

        // 查找同一订单的上一个工序
        Gene prevOperationGene = existingGenes.stream()
                .filter(g -> g.getOrderId() == orderId && g.getOperationId() == operationId - 1)
                .max(Comparator.comparingInt(Gene::getEndTime))
                .orElse(null);

        // 查找设备上一个任务的结束时间
        Gene lastGeneOnMachine = existingGenes.stream()
                .filter(g -> g.getMachineId() == machineId)
                .max(Comparator.comparingInt(Gene::getEndTime))
                .orElse(null);
        int lastMachineTaskEndTime = lastGeneOnMachine != null ? lastGeneOnMachine.getEndTime() : 0;

        if (prevOperationGene != null) {
            // 关键修改：允许前处理时间提前开始
            // 前处理可以在上一个工序结束前开始，最多提前preTime分钟
            int earliestPossibleStart = Math.max(
                    Math.max(prevTime, lastMachineTaskEndTime),
                    prevOperationGene.getEndTime() - preTime // 允许提前preTime分钟
            );

            // 但不能早于上一个工序的开始时间
            earliestPossibleStart = Math.max(earliestPossibleStart, prevOperationGene.getStartTime());

            return earliestPossibleStart;
        }

        return Math.max(prevTime, lastMachineTaskEndTime);
    }
    /**
     * 验证时间安排的合理性
     */
    /**
     * 验证时间安排的合理性
     */
    /**
     * 验证时间安排的合理性
     */
    private boolean validateTimeArrangement(List<Gene> existingGenes, int orderId,
                                            int operationId, int startTime, int endTime,
                                            int preTime, boolean isFirstProductOnMachine) {
        // 验证1：开始时间不能小于0
        if (startTime < 0) {
            return false;
        }

        // 验证2：第一道工序的前处理时间不能提前
        if (operationId == 1 && preTime > 0) {
            // 第一道工序的前处理时间应该从开始时间计算，不能提前
            // 但需要有足够的时间包含前处理时间
            if (endTime - startTime < preTime) {
                return false; // 总时间不足以包含前处理时间
            }
        }

        // 验证3：对于非首道工序，前处理时间不能早于上一个工序的开始时间
        if (operationId > 1 && preTime > 0) {
            Gene prevOperationGene = existingGenes.stream()
                    .filter(g -> g.getOrderId() == orderId && g.getOperationId() == operationId - 1)
                    .max(Comparator.comparingInt(Gene::getStartTime))
                    .orElse(null);

            if (prevOperationGene != null) {
                // 前处理开始时间不能早于上一个工序的开始时间
                if (startTime < prevOperationGene.getStartTime()) {
                    return false;
                }
            }
        }

        // 验证4：结束时间必须大于开始时间
        if (endTime <= startTime) {
            return false;
        }

        // 验证5：总时间必须足够包含所有处理时间
        int totalRequiredTime = preTime + (endTime - startTime - preTime); // 简化计算
        if (endTime - startTime < totalRequiredTime) {
            return false;
        }

        return true;
    }

    /**
     * 计算总处理时间（用于调试和验证）
     */
    private int calculateTotalDuration(Gene gene) {
        return (gene.getEndTime() - gene.getStartTime()) -
                (gene.getPreTime() + gene.getTeardownTime() + gene.getSetupTime());
    }

    // ==================== 原有方法保持不变 ====================

    private List<ScheduleChromosome> removeTrueDuplicates(List<ScheduleChromosome> population) {
        Map<String, ScheduleChromosome> uniqueMap = new LinkedHashMap<>();
        for (ScheduleChromosome chrom : population) {
            String key = generateChromosomeKey(chrom);
            uniqueMap.putIfAbsent(key, chrom);
        }
        return new ArrayList<>(uniqueMap.values());
    }

    private String generateChromosomeKey(ScheduleChromosome chrom) {
        return chrom.getGenes().stream()
                .sorted(Comparator.comparing(Gene::getOrderId)
                        .thenComparing(Gene::getOperationId)
                        .thenComparing(Gene::getStartTime))
                .map(g -> String.format("%d-%d-%d-%d-%d-%d",
                        g.getOrderId(), g.getOperationId(), g.getMachineId(),
                        g.getBatchSize(), g.getStartTime(), g.getEndTime()))
                .collect(Collectors.joining("|"));
    }

    private void CalculateFitness(ScheduleChromosome chromosome) {
        // 1. 最大完工时间
        double makespan = chromosome.getGenes().stream()
                .mapToInt(Gene::getEndTime)
                .max()
                .orElse(0);

        // 2. 总延迟时间
        double tardiness = 0.0;
        Map<Integer, List<Gene>> orderGroups = chromosome.getGenes().stream()
                .collect(Collectors.groupingBy(Gene::getOrderId));

        for (Map.Entry<Integer, List<Gene>> group : orderGroups.entrySet()) {
            int orderCompletion = group.getValue().stream()
                    .mapToInt(Gene::getEndTime)
                    .max()
                    .orElse(0);
            Order order = _orders.stream()
                    .filter(o -> o.getId() == group.getKey())
                    .findFirst()
                    .orElse(null);

            if (order != null) {
                LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion);
                LocalDateTime dueDateTime = order.getDueDate().toLocalDateTime();

                if (completionTime.isAfter(dueDateTime)) {
                    long totalMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, completionTime);
                    double tardinessHours = totalMinutes / 60.0;
                    order.setTardiness(tardinessHours);
                    tardiness += tardinessHours;
                }
            }
        }

        // 3. 总换型时间
        double totalSetupTime = CalculateTotalSetupTime(chromosome);

        // 4. 总流程时间
        double totalFlowTime = CalculateTotalFlowTime(chromosome);

        // 5. 机器负载均衡
        double machineLoadBalance = CalculateMachineLoadBalance(chromosome);

        // 存储目标值
        double finalTardiness = tardiness;
        HashMap<Integer, Double> objMap = new HashMap<>();
        objMap.put(0, makespan);
        objMap.put(1, finalTardiness);
        objMap.put(2, totalSetupTime);
        objMap.put(3, totalFlowTime);
        objMap.put(4, machineLoadBalance);
        chromosome.setObjectiveValues(objMap);

        // 计算适应度
        chromosome.setFitness(
                0.4 * (1.0 / (1 + makespan)) +
                        0.3 * (1.0 / (1 + tardiness)) +
                        0.1 * (1.0 / (1 + totalSetupTime)) +
                        0.1 * (1.0 / (1 + totalFlowTime)) +
                        0.1 * machineLoadBalance
        );
    }

    private double CalculateTotalFlowTime(ScheduleChromosome chromosome) {
        double totalFlowTime = 0.0;
        Map<Integer, List<Gene>> orderGroups = chromosome.getGenes().stream()
                .collect(Collectors.groupingBy(Gene::getOrderId));

        for (Map.Entry<Integer, List<Gene>> group : orderGroups.entrySet()) {
            int minStartTime = group.getValue().stream().mapToInt(Gene::getStartTime).min().orElse(0);
            int maxEndTime = group.getValue().stream().mapToInt(Gene::getEndTime).max().orElse(0);

            LocalDateTime start = chromosome.getBaseTime().plusMinutes(minStartTime);
            LocalDateTime end = chromosome.getBaseTime().plusMinutes(maxEndTime);

            long hours = ChronoUnit.HOURS.between(start, end);
            long minutes = ChronoUnit.MINUTES.between(start, end) % 60;
            totalFlowTime += hours + (double) minutes / 60;
        }

        return totalFlowTime;
    }

    private double CalculateTotalSetupTime(ScheduleChromosome chromosome) {
        double totalSetupTime = 0.0;
        double totalTeardownTime = 0.0;
        double totalPreTime = 0.0;
        Map<Integer, List<Gene>> machineGroups = chromosome.getGenes().stream()
                .collect(Collectors.groupingBy(Gene::getMachineId));

        for (Map.Entry<Integer, List<Gene>> machineGroup : machineGroups.entrySet()) {
            List<Gene> sortedGenes = machineGroup.getValue().stream()
                    .sorted(Comparator.comparingInt(Gene::getStartTime))
                    .collect(Collectors.toList());

            // 累加所有任务的前处理时间和后处理时间
            for (Gene gene : sortedGenes) {
                totalPreTime += gene.getPreTime();
                totalTeardownTime += gene.getTeardownTime();
            }

            // 计算换型时间（仅在产品变化时触发）
            Integer lastProductId = null;
            for (Gene gene : sortedGenes) {
                if (lastProductId != null && lastProductId != gene.getProductId()) {
                    Product product = _products.stream()
                            .filter(p -> p.getId() == gene.getProductId())
                            .findFirst()
                            .orElse(null);
                    if (product == null) continue;

                    Operation operation = product.getOperations().stream()
                            .filter(o -> o.getId() == gene.getOperationId())
                            .findFirst()
                            .orElse(null);
                    if (operation == null) continue;

                    MachineOption machineOption = operation.getMachineOptions().stream()
                            .filter(m -> m.getMachineId() == gene.getMachineId())
                            .findFirst()
                            .orElse(null);
                    if (machineOption != null) {
                        totalSetupTime += machineOption.getSetupTime();
                    }
                }
                lastProductId = gene.getProductId();
            }
        }

        return totalSetupTime + totalPreTime + totalTeardownTime;
    }

    private double CalculateMachineLoadBalance(ScheduleChromosome chromosome) {
        Map<Integer, Double> machineUtilization = new HashMap<>();
        int maxEndTime = chromosome.getGenes().stream()
                .mapToInt(Gene::getEndTime)
                .max()
                .orElse(0);

        if (maxEndTime == 0) return 0.0;

        for (Machine machine : _machines) {
            double busyTime = chromosome.getGenes().stream()
                    .filter(g -> g.getMachineId() == machine.getId())
                    .mapToInt(g -> g.getEndTime() - g.getStartTime())
                    .sum();
            machineUtilization.put(machine.getId(), busyTime / maxEndTime);
        }

        double avgUtilization = machineUtilization.values().stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
        double variance = machineUtilization.values().stream()
                .mapToDouble(u -> Math.pow(u - avgUtilization, 2))
                .average()
                .orElse(0.0);

        return 1.0 / (1 + variance);
    }

    private void RemoveMachineAvailable(Machine machine, GeneDetail geneDetails) {
        List<TimeSegment> timeSegments = new ArrayList<>();

        int index = machine.getAvailability().stream()
                .filter(t -> t.getKey().equals(geneDetails.getKey()))
                .findFirst()
                .map(machine.getAvailability()::indexOf)
                .orElse(-1);

        if (index > -1) {
            TimeSegment targetSegment = machine.getAvailability().get(index);
            LocalDateTime geneEndTime = baseTime.plusMinutes(geneDetails.getEndTime());

            if (targetSegment.getEnd().isAfter(geneEndTime)) {
                TimeSegment usedSegment = new TimeSegment();
                usedSegment.setStart(baseTime.plusMinutes(geneDetails.getStartTime()));
                usedSegment.setEnd(geneEndTime);
                usedSegment.setHoliday(false);
                usedSegment.setKey(UUID.randomUUID().toString());
                usedSegment.setType(SegmentType.REGULAR);
                usedSegment.setUsed(true);
                timeSegments.add(usedSegment);

                geneDetails.setKey(usedSegment.getKey());
                targetSegment.setStart(geneEndTime);
            } else {
                targetSegment.setUsed(true);
            }
        }

        if (!timeSegments.isEmpty()) {
            machine.getAvailability().addAll(timeSegments);
        }
        machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
    }

    private void AddMachineAvailable(Machine machine, List<GeneDetail> geneDetails) {
        if (geneDetails == null || geneDetails.isEmpty()) return;

        for (GeneDetail detail : geneDetails) {
            machine.getAvailability().stream()
                    .filter(t -> t.getKey().equals(detail.getKey()))
                    .findFirst()
                    .ifPresent(t -> t.setUsed(false));
        }

        machine.setAvailability(MergeSegments(machine.getAvailability()));
    }

    private List<TimeSegment> MergeSegments(List<TimeSegment> segments) {
        List<TimeSegment> maintenanceSegments = segments.stream()
                .filter(t -> t.getType() == SegmentType.MAINTENANCE)
                .collect(Collectors.toList());

        List<TimeSegment> unusedRegularSegments = segments.stream()
                .filter(t -> t.getType() != SegmentType.MAINTENANCE && !t.isUsed())
                .collect(Collectors.toList());

        List<TimeSegment> usedRegularSegments = segments.stream()
                .filter(t -> t.getType() != SegmentType.MAINTENANCE && t.isUsed())
                .collect(Collectors.toList());

        unusedRegularSegments.sort(Comparator.comparing(TimeSegment::getStart));

        Deque<TimeSegment> mergedUnused = new ArrayDeque<>();
        for (TimeSegment seg : unusedRegularSegments) {
            if (!mergedUnused.isEmpty() && mergedUnused.peekLast().getEnd().isAfter(seg.getStart())) {
                TimeSegment last = mergedUnused.pollLast();
                last.setEnd(last.getEnd().isAfter(seg.getEnd()) ? last.getEnd() : seg.getEnd());
                mergedUnused.offerLast(last);
            } else {
                mergedUnused.offerLast(seg);
            }
        }

        List<TimeSegment> result = new ArrayList<>(mergedUnused);
        result.addAll(usedRegularSegments);
        result.addAll(maintenanceSegments);
        result.sort(Comparator.comparing(TimeSegment::getStart));

        return result;
    }

    private List<GeneDetail> GetNextAvailableTime(
            Machine machine, int proposedStartTime, int prevtime,
            int processingTime, List<Gene> existingTasks,
            boolean IsInterrupt, boolean istask
    ) {
        LocalDateTime startTime = baseTime.plusMinutes(proposedStartTime);
        String prevtimeStr = prevtime > -1 ? baseTime.plusMinutes(prevtime).toString() : "";

        return FindEarliestStart(machine, processingTime, startTime, prevtimeStr, existingTasks, istask);
    }

    private List<GeneDetail> FindEarliestStart(
            Machine machine, int processingTime, LocalDateTime currentTime,
            String prevtime, List<Gene> existingTasks, boolean checkprevtime
    ) {
        List<Gene> machineTasks = existingTasks.stream()
                .filter(t -> t.getMachineId() == machine.getId())
                .sorted(Comparator.comparingInt(Gene::getStartTime))
                .collect(Collectors.toList());

        List<GeneDetail> times = new ArrayList<>();

        TimeSegment slot = GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime);
        if (slot == null) return times;

        LocalDateTime prevTimeDateTime = StringUtils.isEmpty(prevtime) ? null : LocalDateTime.parse(prevtime);
        LocalDateTime startCandidate = slot.getStart().isAfter(prevTimeDateTime != null ? prevTimeDateTime : currentTime)
                ? slot.getStart()
                : (prevTimeDateTime != null ? prevTimeDateTime : currentTime);
        LocalDateTime endCandidate = startCandidate.plusMinutes(processingTime);

        if (endCandidate.isAfter(slot.getEnd())) {
            return CaldEarliestStart(machine, processingTime, currentTime, prevtime, machineTasks, checkprevtime);
        } else {
            GeneDetail time = new GeneDetail();
            time.setKey(slot.getKey());
            time.setStartTime((int) ChronoUnit.MINUTES.between(baseTime, startCandidate));
            time.setEndTime((int) ChronoUnit.MINUTES.between(baseTime, endCandidate));
            times.add(time);

            RemoveMachineAvailable(machine, time);
            return times;
        }
    }

    private List<GeneDetail> CaldEarliestStart(
            Machine machine, int processingTime, LocalDateTime currentTime,
            String prevtime, List<Gene> machineTasks, boolean checkprevtime
    ) {
        int remainingTime = processingTime;
        LocalDateTime st = StringUtils.isEmpty(prevtime) ? currentTime : LocalDateTime.parse(prevtime);
        LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
        List<GeneDetail> times = new ArrayList<>();
        List<GeneDetail> oldTimes = new ArrayList<>();

        while (remainingTime > 0) {
            TimeSegment shift = GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime);
            if (shift == null) break;

            LocalDateTime shiftStart = shift.getStart();
            LocalDateTime shiftEnd = shift.getEnd();

            // 检查班次间冲突
            if (!prevEnd.isEqual(LocalDateTime.of(2000, 1, 1, 0, 0, 0))) {
                if (prevEnd.isBefore(currentTime)) {
                    // 检查班次间任务
                    LocalDateTime finalPrevEnd = prevEnd;
                    boolean hasTask = machineTasks.stream()
                            .anyMatch(t -> {
                                LocalDateTime taskStart = baseTime.plusMinutes(t.getStartTime());
                                return taskStart.isAfter(finalPrevEnd) && taskStart.isBefore(shiftStart);
                            });

                    if (hasTask) {
                        // 重置状态
                        currentTime = shiftStart;
                        st = shiftStart;
                        remainingTime = processingTime;
                        prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
                        oldTimes.addAll(deepCopyGeneDetailList(times));
                        times.clear();
                        continue;
                    }

                    // 检查班次间维修窗口
                    if (machine.getMaintenanceWindows() != null) {
                        LocalDateTime finalPrevEnd1 = prevEnd;
                        boolean hasMaintenance = machine.getMaintenanceWindows().stream()
                                .anyMatch(w -> w.getStartTime().isAfter(finalPrevEnd1) && w.getStartTime().isBefore(shiftStart));

                        if (hasMaintenance) {
                            currentTime = shiftStart;
                            st = shiftStart;
                            remainingTime = processingTime;
                            prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
                            times.clear();
                            continue;
                        }
                    }
                }
            }

            prevEnd = shiftEnd;
            // 计算有效时间
            LocalDateTime effectiveStart = st.isAfter(shiftStart) ? st : shiftStart;
            long availableMinutes = ChronoUnit.MINUTES.between(effectiveStart, shiftEnd);

            // 处理当前班次
            int processable = Math.min(remainingTime, (int) availableMinutes);
            remainingTime -= processable;
            currentTime = effectiveStart.plusMinutes(processable);

            // 添加时间详情
            GeneDetail time = new GeneDetail();
            time.setKey(shift.getKey());
            time.setStartTime((int) ChronoUnit.MINUTES.between(baseTime, effectiveStart));
            time.setEndTime((int) ChronoUnit.MINUTES.between(baseTime, currentTime));
            times.add(time);
            RemoveMachineAvailable(machine, time);
        }

        // 还原未使用的时间段
        AddMachineAvailable(machine, oldTimes);
        return times;
    }

    private TimeSegment GetCurrentOrNextShift(Machine machine, LocalDateTime time, String prevtime, boolean checkprevtime) {
        TimeSegment start = null;

        // 查找有效班次
        start = machine.getAvailability().stream()
                .filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
                .filter(slot -> slot.getStart().isAfter(time) || slot.getEnd().isAfter(time))
                .findFirst()
                .orElse(null);

        if (start == null) {
            // 生成新时间段
            List<TimeSegment> timeSegments = _machineScheduler.generateTimeSegment(machine, time);
            machine.getAvailability().addAll(timeSegments);

            // 更新设备时间线
            Machine originalMachine = _machines.stream()
                    .filter(t -> t.getId() == machine.getId())
                    .findFirst()
                    .orElse(null);
            if (originalMachine != null) {
                MachineTimeline timeline = _machineScheduler.getOrCreateTimeline(originalMachine);
            }

            // 递归查找
            return GetCurrentOrNextShift(machine, time, prevtime, checkprevtime);
        }

        return start;
    }

    public void PrintScheduleSummary(ScheduleChromosome schedule) {
        System.out.println("\n=== Schedule Summary ===");

        // 按订单分组打印
        Map<Integer, List<Gene>> orderGroups = schedule.getGenes().stream()
                .collect(Collectors.groupingBy(Gene::getOrderId));

        for (Map.Entry<Integer, List<Gene>> group : orderGroups.entrySet()) {
            System.out.printf("\nOrder %d Schedule:%n", group.getKey());

            // 按工序排序
            List<Gene> sortedJobs = group.getValue().stream()
                    .sorted(Comparator.comparingInt(Gene::getOperationId))
                    .collect(Collectors.toList());

            for (Gene job : sortedJobs) {
                Product product = _products.stream()
                        .filter(p -> p.getId() == job.getProductId())
                        .findFirst()
                        .orElse(null);
                Operation operation = product != null ? product.getOperations().stream()
                        .filter(o -> o.getId() == job.getOperationId())
                        .findFirst()
                        .orElse(null) : null;

                if (product != null && operation != null) {
                    String print = String.format(
                            "[%s-%s] Order %d, Product %s, Machine %d, Operation %d, Batch %d, " +
                                    "processingTime %d, preTime %d, setupTime %d, teardownTime %d, " +
                                    "实际加工时间: %d分钟",
                            ConvertTime(job.getStartTime()),
                            ConvertTime(job.getEndTime()),
                            job.getOrderId(),
                            product.getName(),
                            job.getMachineId(),
                            operation.getSequence(),
                            job.getBatchSize(),
                            job.getProcessingTime(),
                            job.getPreTime(),
                            job.getSetupTime(),
                            job.getTeardownTime(),
                            (job.getEndTime() - job.getStartTime()) -
                                    (job.getPreTime() + job.getTeardownTime() + job.getSetupTime())
                    );
                    System.out.println(print);
                }
            }
        }
    }

    public void WriteScheduleSummary(ScheduleChromosome schedule) {
        // 写入日志
        FileHelper.writeLogFile(String.format("\n=== Schedule Summary === 适应度: %f", schedule.getFitness()));
        FileHelper.writeLogFile(String.format("最大完工时间: %f 分钟", schedule.getObjectiveValues().get(0)));
        FileHelper.writeLogFile(String.format("总延迟时间: %f 小时", schedule.getObjectiveValues().get(1)));
        FileHelper.writeLogFile(String.format("总换型时间: %f 分钟", schedule.getObjectiveValues().get(2)));
        FileHelper.writeLogFile(String.format("总流程时间: %f 分钟", schedule.getObjectiveValues().get(3)));
        FileHelper.writeLogFile(String.format("机器负载均衡: %.2f%%", schedule.getObjectiveValues().get(4) * 100));
        FileHelper.writeLogFile("-------------------------");

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

        for (Map.Entry<Integer, List<Gene>> group : orderGroups.entrySet()) {
            FileHelper.writeLogFile(String.format("\n订单 %d 的调度安排:", group.getKey()));

            List<Gene> sortedJobs = group.getValue().stream()
                    .sorted(Comparator.comparingInt(Gene::getOperationId))
                    .collect(Collectors.toList());

            for (Gene job : sortedJobs) {
                Product product = _products.stream()
                        .filter(p -> p.getId() == job.getProductId())
                        .findFirst()
                        .orElse(null);
                Operation operation = product != null ? product.getOperations().stream()
                        .filter(o -> o.getId() == job.getOperationId())
                        .findFirst()
                        .orElse(null) : null;

                if (product != null && operation != null) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(String.format(
                            "[%d-%d]:[%s-%s] 订单%d, 产品%s, 设备%d, 工序%d, 批次%d, " +
                                    "加工%d分钟, 前处理%d分钟, 换型%d分钟, 后处理%d分钟, 总时长%d分钟",
                            job.getStartTime(),
                            job.getEndTime(),
                            ConvertTime(job.getStartTime()),
                            ConvertTime(job.getEndTime()),
                            job.getOrderId(),
                            product.getName(),
                            job.getMachineId(),
                            operation.getSequence(),
                            job.getBatchSize(),
                            job.getProcessingTime(),
                            job.getPreTime(),
                            job.getSetupTime(),
                            job.getTeardownTime(),
                            job.getEndTime() - job.getStartTime()
                    ));

                    // 追加基因详情
                    for (GeneDetail d : job.getGeneDetails()) {
                        sb.append(String.format(
                                "\n\t\t\t\t\t\t\t\t\t\t [%d-%d]:[%s-%s] 时长%d分钟",
                                d.getStartTime(),
                                d.getEndTime(),
                                ConvertTime(d.getStartTime()),
                                ConvertTime(d.getEndTime()),
                                d.getEndTime() - d.getStartTime()
                        ));
                    }

                    FileHelper.writeLogFile(sb.toString());
                }
            }
            FileHelper.writeLogFile("");
        }
    }

    private String ConvertTime(int minute) {
        return baseTime.plusMinutes(minute).format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm"));
    }

    // ========================== 深拷贝工具方法 ==========================
    private List<Product> deepCopyProductList(List<Product> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyProduct).collect(Collectors.toList());
    }

    private Product deepCopyProduct(Product source) {
        if (source == null) return null;
        Product copy = new Product();
        copy.setId(source.getId());
        copy.setName(source.getName());
        copy.setOperations(deepCopyOperationList(source.getOperations()));
        return copy;
    }

    private List<Operation> deepCopyOperationList(List<Operation> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyOperation).collect(Collectors.toList());
    }

    private Operation deepCopyOperation(Operation source) {
        if (source == null) return null;
        Operation copy = new Operation();
        copy.setId(source.getId());
        copy.setProductId(source.getProductId());
        copy.setSequence(source.getSequence());
        copy.setInterrupt(source.isInterrupt());
        copy.setMachineOptions(deepCopyMachineOptionList(source.getMachineOptions()));
        return copy;
    }

    private List<MachineOption> deepCopyMachineOptionList(List<MachineOption> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyMachineOption).collect(Collectors.toList());
    }

    private MachineOption deepCopyMachineOption(MachineOption source) {
        if (source == null) return null;
        MachineOption copy = new MachineOption();
        copy.setMachineId(source.getMachineId());
        copy.setProcessingTime(source.getProcessingTime());
        copy.setPreTime(source.getPreTime());
        copy.setSetupTime(source.getSetupTime());
        copy.setTeardownTime(source.getTeardownTime());
        return copy;
    }

    private List<Machine> deepCopyMachineList(List<Machine> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyMachine).collect(Collectors.toList());
    }

    private Machine deepCopyMachine(Machine source) {
        if (source == null) return null;
        Machine copy = new Machine();
        copy.setId(source.getId());
        copy.setName(source.getName());
        copy.setEarliestTime(source.getEarliestTime());
        copy.setTotalTaskTime(source.getTotalTaskTime());
        copy.setShifts(deepCopyShiftList(source.getShifts()));
        copy.setMaintenanceWindows(deepCopyMaintenanceWindowList(source.getMaintenanceWindows()));
        copy.setAvailability(deepCopyTimeSegmentList(source.getAvailability()));
        copy.setShiftsChanged(source.getShiftsChanged());
        copy.setMaintenanceWindowsChanged(source.getMaintenanceWindowsChanged());
        return copy;
    }

    private List<Shift> deepCopyShiftList(List<Shift> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyShift).collect(Collectors.toList());
    }

    private Shift deepCopyShift(Shift source) {
        if (source == null) return null;
        Shift copy = new Shift();
        copy.setStartTime(source.getStartTime());
        copy.setEndTime(source.getEndTime());
        copy.setDays(source.getDays() != null ? new HashSet<>(source.getDays()) : null);
        copy.setShiftDate(source.getShiftDate());
        copy.setTemporaryShift(source.isTemporaryShift());
        copy.setPriority(source.getPriority());
        copy.setStatus(source.getStatus());
        copy.setMachineId(source.getMachineId());
        copy.setMachineName(source.getMachineName());
        return copy;
    }

    private List<MaintenanceWindow> deepCopyMaintenanceWindowList(List<MaintenanceWindow> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyMaintenanceWindow).collect(Collectors.toList());
    }

    private MaintenanceWindow deepCopyMaintenanceWindow(MaintenanceWindow source) {
        if (source == null) return null;
        MaintenanceWindow copy = new MaintenanceWindow();
        copy.setStartTime(source.getStartTime());
        copy.setEndTime(source.getEndTime());
        copy.setReason(source.getReason());
        return copy;
    }

    private List<TimeSegment> deepCopyTimeSegmentList(List<TimeSegment> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyTimeSegment).collect(Collectors.toList());
    }

    private TimeSegment deepCopyTimeSegment(TimeSegment source) {
        if (source == null) return null;
        TimeSegment copy = new TimeSegment();
        copy.setKey(source.getKey());
        copy.setStart(source.getStart());
        copy.setEnd(source.getEnd());
        copy.setEarliestTime(source.getEarliestTime());
        copy.setTotalTaskTime(source.getTotalTaskTime());
        copy.setType(source.getType());
        copy.setHoliday(source.isHoliday());
        copy.setUsed(source.isUsed());
        return copy;
    }

    private List<Order> deepCopyOrderList(List<Order> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyOrder).collect(Collectors.toList());
    }

    private Order deepCopyOrder(Order source) {
        if (source == null) return null;
        Order copy = new Order();
        copy.setId(source.getId());
        copy.setProductId(source.getProductId());
        copy.setQuantity(source.getQuantity());
        copy.setDueDate(source.getDueDate());
        copy.setOrderCompletion(source.getOrderCompletion());
        copy.setTardiness(source.getTardiness());
        copy.setPriority(source.getPriority());
        copy.setCanSplit(source.isCanSplit());
        copy.setCanInterrupt(source.isCanInterrupt());
        return copy;
    }

    private List<Gene> deepCopyGeneList(List<Gene> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyGene).collect(Collectors.toList());
    }

    private Gene deepCopyGene(Gene source) {
        if (source == null) return null;
        Gene copy = new Gene();
        copy.setOrderId(source.getOrderId());
        copy.setProductId(source.getProductId());
        copy.setOperationId(source.getOperationId());
        copy.setMachineId(source.getMachineId());
        copy.setBatchSize(source.getBatchSize());
        copy.setStartTime(source.getStartTime());
        copy.setEndTime(source.getEndTime());
        copy.setProcessingTime(source.getProcessingTime());
        copy.setPreTime(source.getPreTime());
        copy.setSetupTime(source.getSetupTime());
        copy.setTeardownTime(source.getTeardownTime());
        copy.setOperationName(source.getOperationName());
        copy.setGeneDetails(deepCopyGeneDetailList(source.getGeneDetails()));
        return copy;
    }

    private List<GeneDetail> deepCopyGeneDetailList(List<GeneDetail> source) {
        return source == null ? new ArrayList<>() : source.stream().map(this::deepCopyGeneDetail).collect(Collectors.toList());
    }

    private GeneDetail deepCopyGeneDetail(GeneDetail source) {
        if (source == null) return null;
        GeneDetail copy = new GeneDetail();
        copy.setKey(source.getKey());
        copy.setStartTime(source.getStartTime());
        copy.setEndTime(source.getEndTime());
        return copy;
    }

    private ScheduleChromosome deepCopyScheduleChromosome(ScheduleChromosome source) {
        if (source == null) return null;
        ScheduleChromosome copy = new ScheduleChromosome(source.getBaseTime());
        copy.setGenes(deepCopyGeneList(source.getGenes()));
        copy.setOrders(deepCopyOrderList(source.getOrders()));
        copy.setMachines(deepCopyMachineList(source.getMachines()));
        copy.setObjectiveValues(new HashMap<>(source.getObjectiveValues()));
        copy.setFitness(source.getFitness());
        copy.setTardiness(source.getTardiness());
        return copy;
    }

    // ========================== 辅助类：StringUtils ==========================
    private static class StringUtils {
        public static boolean isEmpty(String str) {
            return str == null || str.trim().isEmpty();
        }
    }







    /**
     * 计算绝对开始时间（考虑设备日历+前处理+换型时间，跨时段自动拆分）
     */
    /**
     * 计算绝对开始时间（完善边界处理：结束点自动顺延）
     */
    /**
     * 计算绝对开始时间（前处理+换型时间不跨设备非工作时段，仅占用当前可用时段）
     * 核心：前处理时间最多用到当前可用时段结束点，不顺延到下一个时段
     */
    private int calculateAbsoluteStartTime(Gene gene, MachineOption machineOption) {
        int startTime = gene.getStartTime(); // 基因开始时间（相对baseTime分钟数）
        int setupTime = gene.getSetupTime(); // 换型时间（分钟）
        int preTime = gene.getPreTime();     // 前处理时间（分钟）
        int totalPrepTime = setupTime + preTime;

        if (totalPrepTime <= 0) {
            // 无准备时间，直接返回基因开始时间（按日历调整边界）
            return adjustTimeByMachineCalendar(gene.getMachineId(), startTime, true);
        }

        // 获取目标设备（深拷贝，避免污染原状态）
        Machine targetMachine = deepCopyMachine(
                _machines.stream()
                        .filter(m -> m.getId() == gene.getMachineId())
                        .findFirst()
                        .orElseThrow(() -> new NoSuchElementException("Machine not found: " + gene.getMachineId()))
        );

        // 步骤1：找到基因开始时间所在的“当前可用时段”
        LocalDateTime geneStartDateTime = baseTime.plusMinutes(startTime);
        TimeSegment currentAvailableSegment = findCurrentAvailableSegment(targetMachine, geneStartDateTime);

        if (currentAvailableSegment == null) {
            // 无当前可用时段，兜底返回原计算值
            int fallbackTime = adjustTimeByMachineCalendar(gene.getMachineId(), startTime, true);
            System.out.printf("设备%d：无当前可用时段，兜底绝对开始时间=%d（%s）%n",
                    targetMachine.getId(), fallbackTime, ConvertTime(fallbackTime));
            return fallbackTime;
        }

        // 步骤2：计算当前可用时段的“剩余时间”（从基因开始时间到时段结束点）
        long segmentRemainingMinutes = ChronoUnit.MINUTES.between(
                geneStartDateTime,
                currentAvailableSegment.getEnd()
        );
        int usablePrepTime = (int) Math.min(totalPrepTime, segmentRemainingMinutes);

        // 步骤3：绝对开始时间 = 基因开始时间 + 实际可用的准备时间（不跨时段）
        int absoluteStartTime = startTime + usablePrepTime;

        // 步骤4：边界校验（确保不超过当前时段结束点）
        LocalDateTime absoluteStartDateTime = baseTime.plusMinutes(absoluteStartTime);
        if (absoluteStartDateTime.isAfter(currentAvailableSegment.getEnd())) {
            absoluteStartTime = (int) ChronoUnit.MINUTES.between(baseTime, currentAvailableSegment.getEnd());
        }

        // 步骤5：最终按日历调整（避免落在时段结束点）
        absoluteStartTime = adjustTimeByMachineCalendar(gene.getMachineId(), absoluteStartTime, true);


        return absoluteStartTime;
    }

    /**
     * 辅助方法：找到指定时间所在的“当前可用时段”（未占用、非维修、包含该时间）
     */
    private TimeSegment findCurrentAvailableSegment(Machine machine, LocalDateTime targetTime) {
        return machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed()) // 未被占用
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE) // 非维修时段
                .filter(segment -> {
                    // 包含目标时间（且目标时间不是时段结束点）
                    boolean isAfterStart = !targetTime.isBefore(segment.getStart());
                    boolean isBeforeEnd = targetTime.isBefore(segment.getEnd());
                    return isAfterStart && isBeforeEnd;
                })
                .findFirst()
                .orElse(null);
    }

    /**
     * 计算绝对结束时间（考虑设备日历+后处理时间）
     */
    /**
     * 计算绝对结束时间（完善边界处理）
     */
    /**
     * 计算绝对结束时间（正确逻辑：基因结束时间 - 后处理时间 + 设备日历调整）
     * 绝对结束时间 = 加工完成时间（后处理开始前的时间）
     */
    private int calculateAbsoluteEndTime(Gene gene, MachineOption machineOption) {
        int geneEndTime = gene.getEndTime();         // 基因的结束时间（含后处理，相对baseTime的分钟数）
        int teardownTime = gene.getTeardownTime();   // 后处理时间（分钟，加工完成后执行）

        // 无后处理时间：绝对结束时间=基因结束时间（直接按日历调整）
        if (teardownTime <= 0) {
            return adjustTimeByMachineCalendar(gene.getMachineId(), geneEndTime, false);
        }

        // 核心：加工完成时间 = 基因结束时间 - 后处理时间（后处理在加工完成后执行）
        int processCompletionTime = geneEndTime - teardownTime;

        // 校验：加工完成时间不能早于基因开始时间（避免逻辑矛盾）
        if (processCompletionTime < gene.getStartTime()) {
            System.out.printf("设备%d：订单%d工序%d - 后处理时间%d分钟过长，基因结束时间%d < 开始时间%d，兜底为基因开始时间%n",
                    gene.getMachineId(), gene.getOrderId(), gene.getOperationId(),
                    teardownTime, geneEndTime, gene.getStartTime());
            processCompletionTime = gene.getStartTime();
        }

        // 按设备日历调整（处理非工作时段、结束点边界）
        int absoluteEndTime = adjustTimeByMachineCalendar(gene.getMachineId(), processCompletionTime, false);

        // 最终校验：调整后的绝对结束时间不能早于基因开始时间
        absoluteEndTime = Math.max(absoluteEndTime, gene.getStartTime());

        // 日志输出（清晰展示计算链路）
        System.out.printf("设备%d：基因结束时间=%d（%s），后处理%d分钟 → 加工完成时间=%d（%s）→ 调整后绝对结束时间=%d（%s）%n",
                gene.getMachineId(),
                geneEndTime, ConvertTime(geneEndTime),
                teardownTime,
                processCompletionTime, ConvertTime(processCompletionTime),
                absoluteEndTime, ConvertTime(absoluteEndTime));

        return absoluteEndTime;
    }


    /**
     * 根据设备日历调整时间（处理边界情况：时间=时段结束点→顺延到下一个可用时段）
     */
    private int adjustTimeByMachineCalendar(Machine machine, int proposedTime, boolean isStartTime) {
        LocalDateTime proposedDateTime = baseTime.plusMinutes(proposedTime);

        // 查找包含提议时间的可用时段（排除维修时段、已占用时段）
        TimeSegment availableSegment = machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed())
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                .filter(segment -> {
                    // 关键修改：包含「时段内」但排除「时段结束点」（结束点视为不可用）
                    boolean isAfterStart = !proposedDateTime.isBefore(segment.getStart());
                    boolean isBeforeEnd = proposedDateTime.isBefore(segment.getEnd()); // 用isBefore替代!isAfter
                    return isAfterStart && isBeforeEnd;
                })
                .findFirst()
                .orElse(null);

        if (availableSegment != null) {
            return proposedTime; // 时间在可用时段内（非结束点），无需调整
        }

        // 情况1：提议时间是开始时间 → 查找下一个可用时段的开始时间
        if (isStartTime) {
            TimeSegment nextSegment = machine.getAvailability().stream()
                    .filter(segment -> !segment.isUsed())
                    .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                    .filter(segment -> segment.getStart().isAfter(proposedDateTime))
                    .min(Comparator.comparing(TimeSegment::getStart))
                    .orElse(null);

            if (nextSegment != null) {
                int adjustedTime = (int) ChronoUnit.MINUTES.between(baseTime, nextSegment.getStart());
                System.out.printf("设备%d：开始时间%d（%s）是时段结束点/非可用时间，顺延到下一个可用时段开始时间%d（%s）%n",
                        machine.getId(), proposedTime, ConvertTime(proposedTime),
                        adjustedTime, ConvertTime(adjustedTime));
                return adjustedTime;
            }
        }
        // 情况2：提议时间是结束时间 → 查找前一个可用时段的结束时间（避免跨时段）
        else {
            TimeSegment prevSegment = machine.getAvailability().stream()
                    .filter(segment -> !segment.isUsed())
                    .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                    .filter(segment -> segment.getEnd().isBefore(proposedDateTime))
                    .max(Comparator.comparing(TimeSegment::getEnd))
                    .orElse(null);

            if (prevSegment != null) {
                return (int) ChronoUnit.MINUTES.between(baseTime, prevSegment.getEnd());
            }
        }

        // 兜底：无可用时段时返回原时间（理论上不会发生）
        return proposedTime;
    }


    /**
     * 按设备ID查询可用时间（复用adjustTimeByMachineCalendar逻辑）
     */
    private int adjustTimeByMachineCalendar(int machineId, int proposedTime, boolean isStartTime) {
        Machine machine = _machines.stream()
                .filter(m -> m.getId() == machineId)
                .findFirst()
                .orElse(null);

        if (machine == null) {
            return proposedTime;
        }

        return adjustTimeByMachineCalendar(machine, proposedTime, isStartTime);
    }


    /**
     * 计算绝对准备时间（考虑设备日历，跳过非工作时间）
     */
    private int calculateAbsolutePreparationTime(Gene gene, MachineOption machineOption) {


        int totalPreparationTime = gene.getPreTime(); // 总准备时间

        if (totalPreparationTime <= 0) {
            return 0; // 没有准备时间
        }

        // 获取设备
        Machine machine = _machines.stream()
                .filter(m -> m.getId() == gene.getMachineId())
                .findFirst()
                .orElse(null);

        if (machine == null) {
            return totalPreparationTime; // 找不到设备，返回原始时间
        }

        // 开始时间（基因开始时间）
        int startTime = gene.getStartTime();
        LocalDateTime currentTime = baseTime.plusMinutes(startTime);



        // 计算考虑日历的实际准备时间
        return calculateCalendarAdjustedTime(machine, currentTime, totalPreparationTime);
    }



    /**
     * 计算绝对换型时间（考虑设备日历，跳过非工作时间）
     */
    private int calculateAbsoluteSetupTime(Gene gene, MachineOption machineOption) {


        int totalPreparationTime = gene.getSetupTime(); // 总准备时间

        if (totalPreparationTime <= 0) {
            return 0; // 没有准备时间
        }

        // 获取设备
        Machine machine = _machines.stream()
                .filter(m -> m.getId() == gene.getMachineId())
                .findFirst()
                .orElse(null);

        if (machine == null) {
            return totalPreparationTime; // 找不到设备，返回原始时间
        }

        // 开始时间（基因开始时间）
        int startTime = gene.getStartTime();
        LocalDateTime currentTime = baseTime.plusMinutes(startTime);



        // 计算考虑日历的实际准备时间
        return calculateCalendarAdjustedTime(machine, currentTime, totalPreparationTime);
    }


    /**
     * 计算考虑设备日历的时间（跳过非工作时间）
     */
    private int calculateCalendarAdjustedTime(Machine machine, LocalDateTime startTime, int requiredMinutes) {
        LocalDateTime currentTime = startTime;
        int remainingMinutes = requiredMinutes;
        int totalElapsedMinutes = 0; // 实际经过的分钟数（包含非工作时间）

        System.out.printf("  开始计算: %s, 需要%d分钟%n",
                startTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")),
                requiredMinutes);

        while (remainingMinutes > 0) {
            // 查找包含当前时间的可用时间段
            TimeSegment currentSegment = findAvailableSegmentAtTime(machine, currentTime);

            if (currentSegment == null) {
                // 没有找到可用时间段，查找下一个可用时间段
                TimeSegment nextSegment = findNextAvailableSegment(machine, currentTime);
                if (nextSegment == null) {
                    System.out.printf("  警告: 找不到后续可用时间段，剩余%d分钟无法安排%n", remainingMinutes);
                    break; // 无法安排剩余时间
                }

                // 跳到下一个可用时间段的开始
                long jumpMinutes = ChronoUnit.MINUTES.between(currentTime, nextSegment.getStart());
                totalElapsedMinutes += (int) jumpMinutes;
                currentTime = nextSegment.getStart();
                System.out.printf("  跳过非工作时间: 跳转%d分钟到 %s%n",
                        jumpMinutes, currentTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")));
                continue;
            }

            // 计算当前时间段可用的分钟数
            long availableMinutesInSegment = ChronoUnit.MINUTES.between(currentTime, currentSegment.getEnd());
            int processableMinutes = (int) Math.min(remainingMinutes, availableMinutesInSegment);

            // 处理当前时间段
            remainingMinutes -= processableMinutes;
            totalElapsedMinutes += processableMinutes;
            currentTime = currentTime.plusMinutes(processableMinutes);

            System.out.printf("  在当前时间段处理%d分钟: %s → %s, 剩余%d分钟%n",
                    processableMinutes,
                    currentTime.minusMinutes(processableMinutes).format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")),
                    currentTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")),
                    remainingMinutes);

            // 如果当前时间段用完但还有剩余时间，移动到时间段结束点
            if (remainingMinutes > 0 && currentTime.equals(currentSegment.getEnd())) {
                // 查找下一个时间段
                TimeSegment nextSegment = findNextAvailableSegment(machine, currentTime);
                if (nextSegment == null) {
                    System.out.printf("  警告: 当前时间段用完，但找不到后续时间段，剩余%d分钟无法安排%n", remainingMinutes);
                    break;
                }

                // 跳到下一个时间段的开始
                long jumpMinutes = ChronoUnit.MINUTES.between(currentTime, nextSegment.getStart());
                totalElapsedMinutes += (int) jumpMinutes;
                currentTime = nextSegment.getStart();
                System.out.printf("  时间段结束，跳转到下一个: 跳转%d分钟到 %s%n",
                        jumpMinutes, currentTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")));
            }
        }

        System.out.printf("  计算完成: 原始需要%d分钟，实际经过%d分钟%n", requiredMinutes, totalElapsedMinutes);
        return totalElapsedMinutes;
    }

    /**
     * 查找包含指定时间的可用时间段
     */
    private TimeSegment findAvailableSegmentAtTime(Machine machine, LocalDateTime time) {
        return machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed())
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                .filter(segment ->
                        !segment.getStart().isAfter(time) &&
                                segment.getEnd().isAfter(time))
                .findFirst()
                .orElse(null);
    }

    /**
     * 查找下一个可用时间段
     */
    private TimeSegment findNextAvailableSegment(Machine machine, LocalDateTime afterTime) {
        return machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed())
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                .filter(segment -> segment.getStart().isAfter(afterTime))
                .min(Comparator.comparing(TimeSegment::getStart))
                .orElse(null);
    }


    /**
     * 反向查找：找到包含指定时间的可用工作时段（用于向前追溯）
     */
    private TimeSegment findAvailableSegmentAtTimeReverse(Machine machine, LocalDateTime time) {
        return machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed())
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                .filter(segment -> !segment.isHoliday())
                .filter(segment -> {
                    boolean isAfterStart = !time.isBefore(segment.getStart());
                    boolean isBeforeEnd = time.isBefore(segment.getEnd());
                    return isAfterStart && isBeforeEnd;
                })
                .findFirst()
                .orElse(null);
    }


    /**
     * 查找前一个可用时间段
     */
    private TimeSegment findPreviousAvailableSegment(Machine machine, LocalDateTime beforeTime) {
        return machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed())
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                .filter(segment -> segment.getEnd().isBefore(beforeTime))
                .max(Comparator.comparing(TimeSegment::getEnd))
                .orElse(null);
    }


    /**
     * 计算绝对后处理时间（从结束时间向前计算，考虑设备日历，跳过非工作时间）
     * 后处理时间是从加工完成时间向前安排的
     */
    private int calculateAbsoluteTeardownTime(Gene gene, MachineOption machineOption) {
        int teardownTime = gene.getTeardownTime(); // 后处理时间

        if (teardownTime <= 0) {
            return 0; // 没有后处理时间
        }

        // 获取设备
        Machine machine = _machines.stream()
                .filter(m -> m.getId() == gene.getMachineId())
                .findFirst()
                .orElse(null);

        if (machine == null) {
            return teardownTime; // 找不到设备，返回原始时间
        }

        // 后处理结束时间 = 基因结束时间（包含后处理的时间）
        int endTime = gene.getEndTime();
        LocalDateTime endDateTime = baseTime.plusMinutes(endTime);

        System.out.printf("计算绝对后处理时间 - 设备%d: 结束时间=%d (%s), 后处理时间=%d分钟%n",
                machine.getId(), endTime, ConvertTime(endTime), teardownTime);

        // 计算考虑日历的实际后处理时间（向前计算）
        return calculateCalendarAdjustedTimeBackward(machine, endDateTime, teardownTime);
    }


    /**
     * 向后计算考虑设备日历的时间（从结束时间向前回溯，跳过非工作时间）
     */
    private int calculateCalendarAdjustedTimeBackward(Machine machine, LocalDateTime endTime, int requiredMinutes) {
        LocalDateTime currentTime = endTime;
        int remainingMinutes = requiredMinutes;
        int totalElapsedMinutes = 0; // 实际经过的分钟数（包含非工作时间）

        System.out.printf("  开始向后计算后处理时间: 结束时间=%s, 需要%d分钟%n",
                endTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")),
                requiredMinutes);

        while (remainingMinutes > 0) {
            // 查找包含当前时间的可用时间段（向前查找）
            TimeSegment currentSegment = findAvailableSegmentAtTimeBackward(machine, currentTime);

            if (currentSegment == null) {
                // 没有找到可用时间段，查找前一个可用时间段
                TimeSegment prevSegment = findPreviousAvailableSegment(machine, currentTime);
                if (prevSegment == null) {
                    System.out.printf("  警告: 找不到前续可用时间段，剩余%d分钟无法安排%n", remainingMinutes);
                    break; // 无法安排剩余时间
                }

                // 跳到前一个可用时间段的结束时间
                long jumpMinutes = ChronoUnit.MINUTES.between(prevSegment.getEnd(), currentTime);
                totalElapsedMinutes += (int) jumpMinutes;
                currentTime = prevSegment.getEnd();
                System.out.printf("  跳过非工作时间: 向后跳转%d分钟到 %s%n",
                        jumpMinutes, currentTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")));
                continue;
            }

            // 计算当前时间段可用的分钟数（向前计算）
            long availableMinutesInSegment = ChronoUnit.MINUTES.between(currentSegment.getStart(), currentTime);
            int processableMinutes = (int) Math.min(remainingMinutes, availableMinutesInSegment);

            // 处理当前时间段（向前移动）
            remainingMinutes -= processableMinutes;
            totalElapsedMinutes += processableMinutes;
            currentTime = currentTime.minusMinutes(processableMinutes);

            System.out.printf("  在当前时间段处理%d分钟: %s ← %s, 剩余%d分钟%n",
                    processableMinutes,
                    currentTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")),
                    currentTime.plusMinutes(processableMinutes).format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")),
                    remainingMinutes);

            // 如果当前时间段用完但还有剩余时间，移动到时间段开始点
            if (remainingMinutes > 0 && currentTime.equals(currentSegment.getStart())) {
                // 查找前一个时间段
                TimeSegment prevSegment = findPreviousAvailableSegment(machine, currentTime);
                if (prevSegment == null) {
                    System.out.printf("  警告: 当前时间段用完，但找不到前续时间段，剩余%d分钟无法安排%n", remainingMinutes);
                    break;
                }

                // 跳到前一个时间段的结束时间
                long jumpMinutes = ChronoUnit.MINUTES.between(prevSegment.getEnd(), currentTime);
                totalElapsedMinutes += (int) jumpMinutes;
                currentTime = prevSegment.getEnd();
                System.out.printf("  时间段开始，跳转到前一个: 向后跳转%d分钟到 %s%n",
                        jumpMinutes, currentTime.format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")));
            }
        }

        System.out.printf("  后处理时间计算完成: 原始需要%d分钟，实际经过%d分钟%n", requiredMinutes, totalElapsedMinutes);
        return totalElapsedMinutes;
    }

    /**
     * 向后查找包含指定时间的可用时间段
     */
    private TimeSegment findAvailableSegmentAtTimeBackward(Machine machine, LocalDateTime time) {
        return machine.getAvailability().stream()
                .filter(segment -> !segment.isUsed())
                .filter(segment -> segment.getType() != SegmentType.MAINTENANCE)
                .filter(segment -> {
                    // 包含目标时间（且目标时间不是时段开始点）
                    boolean isAfterStart = time.isAfter(segment.getStart());
                    boolean isBeforeEnd = !time.isAfter(segment.getEnd()); // 用!isAfter替代isBefore
                    return isAfterStart && isBeforeEnd;
                })
                .findFirst()
                .orElse(null);
    }



}