package com.aps.service.Algorithm;

import com.aps.common.util.FileHelper;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.ScheduleResultDetail;
import com.aps.entity.basic.*;

import com.aps.service.plan.MachineSchedulerService;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * 作者：佟礼
 * 时间：2025-11-24
 */
public class MachineCalculator {
    private LocalDateTime baseTime;
    private final List<Machine> machines;
    private final MachineSchedulerService machineScheduler;

    public MachineCalculator(LocalDateTime baseTime, List<Machine> machines, MachineSchedulerService machineScheduler) {
        this.baseTime = baseTime;
        this.machines = machines;

        this.machineScheduler = machineScheduler;

    }



    /**
     * 获取机器下一个可用时间窗口（考虑班次约束）
     */
    // 从 proposedStartTime 开始查找机台下一段可排窗口；必要时会把命中的 availability 临时标记为已占用。
    public CopyOnWriteArrayList<ScheduleResultDetail> getNextAvailableTime(Machine machine,Entry operation, int proposedStartTime,
                                                            int prevtime, int processingTime,
                                                           CopyOnWriteArrayList<GAScheduleResult> existingTasks,
                                                            boolean isInterrupt, boolean istask,
                                                            double oneTime,double quantity,
                                                            boolean islockMachineTime,boolean isJit) {
        LocalDateTime startTime = baseTime.plus(proposedStartTime, ChronoUnit.SECONDS);

        String prevtimestr = "";
        if (prevtime > -1) {
            prevtimestr = baseTime.plus(prevtime, ChronoUnit.SECONDS)
                    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }

        // 查找合适的班次窗口
        return findEarliestStart(machine,  operation,processingTime, startTime, prevtimestr,
                existingTasks, oneTime, quantity, istask, islockMachineTime,isInterrupt,isJit);
    }

    public CopyOnWriteArrayList<TimeSegment> getMachineAvailableTime(Machine machine, int proposedStartTime,
                                                                            int processingTime,
                                                                           CopyOnWriteArrayList<GAScheduleResult> existingTasks,
                                                                           boolean isInterrupt) {
        LocalDateTime startTime = baseTime.plus(proposedStartTime, ChronoUnit.SECONDS);

        // 查找合适的班次窗口
        return   findAvailableSegments(machine, startTime, existingTasks, processingTime, isInterrupt);
    }

    // 基于已选可用时段组装排程结果，并把换型段/加工段对应的 availability 临时占用。
    // ==================== 倒排换型排程辅助方法开始 ====================

    /**
     * 倒排生成排程明细：从 latestEndTime 往前找加工可用段，可选地在加工段前拼上换型段。
     * 返回值沿用老结构：1=换型时间，2=ScheduleResultDetail 列表。
     */
    public Map<Integer,Object> CreateScheduleResultBackward(
            Machine machine, Entry operation, int processingTime, int latestEndTime,
            double oneTime, double quantity, int changeOverTime, int setupStartTime,
            int setupEndTime, CopyOnWriteArrayList<TimeSegment> setupSegments,
            boolean setupInCalendarTime) {

        Map<Integer,Object> result = new HashMap<>(2);
        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();
        CopyOnWriteArrayList<TimeSegment> usedSegments = new CopyOnWriteArrayList<>();

        times.addAll(CreateSetupDetailsBackward(machine, changeOverTime, setupStartTime, setupEndTime,
                setupSegments, setupInCalendarTime));

        LocalDateTime cursor = baseTime.plusSeconds(latestEndTime);
        int remainingTime = processingTime;
        final LocalDateTime processSearchEnd = cursor;


        List<TimeSegment> processSegments = machine.getAvailability().stream()
                .filter(slot -> !slot.isUsed())
                .filter(slot -> slot.getType() != SegmentType.MAINTENANCE)
                .filter(slot -> slot.getStart().isBefore(processSearchEnd))
                .sorted(Comparator.comparing(TimeSegment::getEnd).reversed())
                .collect(Collectors.toList());
        double totalAvailableSeconds = calculateTotalAvailableSecond(
                new CopyOnWriteArrayList<>(processSegments), processSearchEnd, true);
        if (totalAvailableSeconds + 0.0001 < processingTime) {
            throw new IllegalStateException(buildInsufficientScheduleMessage(machine, operation,
                    processingTime, totalAvailableSeconds, processSegments.size()));
        }

        for (TimeSegment slot : processSegments) {
            if (remainingTime <= 0) {
                break;
            }

            LocalDateTime effectiveEnd = slot.getEnd().isAfter(cursor) ? cursor : slot.getEnd();
            if (!slot.getStart().isBefore(effectiveEnd)) {
                continue;
            }

            long availableSeconds = ChronoUnit.SECONDS.between(slot.getStart(), effectiveEnd);
            long effectiveSeconds = Math.round(availableSeconds * slot.getEfficiency());
            if (effectiveSeconds <= 0) {
                continue;
            }

            int processable = Math.min(remainingTime, (int) effectiveSeconds);
            int calendarSeconds = (int) Math.ceil(processable / slot.getEfficiency());
            LocalDateTime effectiveStart = effectiveEnd.minusSeconds(calendarSeconds);

            ScheduleResultDetail time = createScheduleDetail(slot, effectiveStart, effectiveEnd,
                    processable, oneTime, quantity, false);
            times.add(time);

            CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time, slot);
            if (usedSegments1 != null && usedSegments1.size() > 0) {
                usedSegments.addAll(usedSegments1);
            }

            remainingTime -= processable;
            cursor = effectiveStart;
        }

        if (remainingTime > 0) {
            throw new IllegalStateException(buildInsufficientScheduleMessage(machine, operation,
                    processingTime, totalAvailableSeconds, processSegments.size()));
        }

        if (usedSegments != null && usedSegments.size() > 0) {
            machine.getAvailability().addAll(usedSegments);
        }
        machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
        times.sort(Comparator.comparingInt(ScheduleResultDetail::getStartTime));

        result.put(1, changeOverTime);
        result.put(2, times);
        return result;
    }

    /**
     * 生成倒排换型明细，并按配置决定换型是否占用设备日历工作段。
     */
    public CopyOnWriteArrayList<ScheduleResultDetail> CreateSetupDetailsBackward(
            Machine machine, int changeOverTime, int setupStartTime, int setupEndTime,
            CopyOnWriteArrayList<TimeSegment> setupSegments, boolean setupInCalendarTime) {
        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();

        if (setupInCalendarTime && changeOverTime > 0 && setupEndTime > setupStartTime) {
            ScheduleResultDetail setupDetail = new ScheduleResultDetail();
            setupDetail.setKey(UUID.randomUUID().toString());
            setupDetail.setStartTime(setupStartTime);
            setupDetail.setEndTime(setupEndTime);
            setupDetail.setSetup(true);

            if (setupSegments != null && setupSegments.size() > 0) {
                List<TimeSegment> occupiedSetupSegments = new ArrayList<>();
                for (TimeSegment setupSegment : setupSegments) {
                    ScheduleResultDetail occupiedSetupDetail = occupySetupSegment(machine, setupSegment);
                    if (occupiedSetupDetail != null && occupiedSetupDetail.getKey() != null) {
                        TimeSegment keyRef = new TimeSegment();
                        keyRef.setKey(occupiedSetupDetail.getKey());
                        keyRef.setStart(baseTime.plusSeconds(occupiedSetupDetail.getStartTime()));
                        keyRef.setEnd(baseTime.plusSeconds(occupiedSetupDetail.getEndTime()));
                        occupiedSetupSegments.add(keyRef);
                    }
                }
                setupDetail.setUsedSegment(occupiedSetupSegments);
            }
            times.add(setupDetail);
        } else if (setupSegments != null && setupSegments.size() > 0) {
            for (TimeSegment setupSegment : setupSegments) {
                ScheduleResultDetail setupDetail = occupySetupSegment(machine, setupSegment);
                if (setupDetail != null) {
                    times.add(setupDetail);
                }
            }
        } else if (changeOverTime > 0 && setupEndTime > setupStartTime) {
            ScheduleResultDetail setupDetail = new ScheduleResultDetail();
            setupDetail.setStartTime(setupStartTime);
            setupDetail.setEndTime(setupEndTime);
            setupDetail.setSetup(true);
            times.add(setupDetail);
        }

        if (machine != null && machine.getAvailability() != null) {
            machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
        }
        return times;
    }

    private ScheduleResultDetail occupySetupSegment(Machine machine, TimeSegment setupSegment) {
        if (machine == null || setupSegment == null || !setupSegment.getStart().isBefore(setupSegment.getEnd())) {
            return null;
        }

        TimeSegment targetSegment = machine.getAvailability().stream()
                .filter(slot -> !slot.isUsed())
                .filter(slot -> slot.getType() != SegmentType.MAINTENANCE)
                .filter(slot -> slot.getStart().compareTo(setupSegment.getStart()) <= 0)
                .filter(slot -> slot.getEnd().compareTo(setupSegment.getEnd()) >= 0)
                .findFirst()
                .orElse(null);
        if (targetSegment == null) {
            return null;
        }

        ScheduleResultDetail setupDetail = new ScheduleResultDetail();
        setupDetail.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, setupSegment.getStart()));
        setupDetail.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, setupSegment.getEnd()));
        setupDetail.setSetup(true);
        setupDetail.setKey(targetSegment.getKey());

        CopyOnWriteArrayList<TimeSegment> usedSegments = RemoveMachineAvailable(machine, setupDetail, targetSegment);
        if (usedSegments != null && usedSegments.size() > 0) {
            machine.getAvailability().addAll(usedSegments);
        }
        return setupDetail;
    }

    private ScheduleResultDetail createScheduleDetail(TimeSegment slot, LocalDateTime startTime,
                                                      LocalDateTime endTime, int processable,
                                                      double oneTime, double quantity,
                                                      boolean useWholeQuantity) {
        ScheduleResultDetail time = new ScheduleResultDetail();
        time.setKey(slot.getKey());
        time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, startTime));
        time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, endTime));
        time.setEfficiency(slot.getEfficiency());
        time.setOneTime(oneTime);
        if (useWholeQuantity) {
            time.setQuantity(quantity);
        } else if (oneTime > 0) {
            BigDecimal bd = new BigDecimal(String.valueOf(processable / oneTime));
            time.setQuantity(bd.setScale(4, RoundingMode.HALF_UP).doubleValue());
        }
        return time;
    }

    private String buildInsufficientScheduleMessage(Machine machine, Entry operation,
                                                    int requiredSeconds, double availableSeconds, int segmentCount) {
        String machineId = machine == null ? "null" : String.valueOf(machine.getId());
        String machineName = machine == null ? "" : String.valueOf(machine.getName());
        String operationId = operation == null ? "null" : String.valueOf(operation.getId());
        String groupId = operation == null ? "null" : String.valueOf(operation.getGroupId());
        return String.format("设备可用时间不足，machineId=%s, machineName=%s, operationId=%s, groupId=%s, requiredSeconds=%d, availableSeconds=%.0f, segmentCount=%d",
                machineId, machineName, operationId, groupId, requiredSeconds, availableSeconds, segmentCount);
    }

    // ==================== 倒排换型排程辅助方法结束 ====================

    public Map<Integer,Object> CreateScheduleResult(
            Machine machine,Entry operation, int processingTime, int proposedStartTime,CopyOnWriteArrayList<TimeSegment> timeSegments,
            double oneTime,double quantity
            ,boolean isInterrupt,int changeOvertTime,boolean changeOverInWeek,int setupStartTime,boolean islockMachineTime,boolean isJit) {

        LocalDateTime startTime = baseTime.plus(proposedStartTime, ChronoUnit.SECONDS);

        Map<Integer,Object> result=new HashMap<>(2);
        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();
        int ChangeOverTimenew=0;
        CopyOnWriteArrayList<TimeSegment> usedSegments=new CopyOnWriteArrayList<>();
        if(changeOverInWeek)
        {
            // 换型时间完全在休息时间
            LocalDateTime setupStartTime1 = baseTime.plusSeconds(setupStartTime);
            ChangeOverTimenew=changeOvertTime;
           int changeOvertTime_end=setupStartTime+changeOvertTime;
            LocalDateTime setupendTime1 = baseTime.plusSeconds(changeOvertTime_end);

            List<TimeSegment> setuptime=  machine.getAvailability()
                    .stream()
                    .filter(t->((t.getStart().compareTo(setupStartTime1)>=0)
                            &&t.getEnd().compareTo(setupendTime1)<=0)||((t.getStart().compareTo(setupStartTime1)<=0)
                            &&t.getEnd().compareTo(setupStartTime1)>0))
                    .sorted(Comparator.comparing(TimeSegment::getStart))
                    .collect(Collectors.toList());

           if(setuptime!=null&&setuptime.size()>0)
           {
               TimeSegment shift1 = setuptime.get(0);
               LocalDateTime shiftStart1 = shift1.getStart();
               //判断换型开始时间是否在工作时间段内，要占用工作时间，分割工作时间
                if(setupStartTime1.compareTo(shiftStart1)>0)
               {
                   //换型时间不考虑效率系数
                   ScheduleResultDetail time =new ScheduleResultDetail();
                   time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, setupStartTime1));
                   time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, shift1.getEnd()));

                   CopyOnWriteArrayList<TimeSegment> usedSegments1=  RemoveMachineAvailable(machine, time,shift1,false);
                   if (usedSegments1 != null && usedSegments1.size() > 0) {
                       usedSegments.addAll(usedSegments1);
                   }
                   if(islockMachineTime) {
                       for (int i = 1; i < setuptime.size(); i++) {
                           TimeSegment se = setuptime.get(i);
                           se.setUsed(true);
                       }
                   }
               }else {
                    if(islockMachineTime) {
                        for (TimeSegment se : setuptime) {
                            se.setUsed(true);
                        }
                    }
                }


//               int i = 0;
//               while (changeOvertTime > 0) {
//                   TimeSegment shift = setuptime.get(i);
//                   LocalDateTime shiftStart = shift.getStart();
//                   LocalDateTime shiftEnd = shift.getEnd();
//                   long availableSeconds = ChronoUnit.SECONDS.between(shiftStart, shiftEnd);
//                   int processable = Math.min(changeOvertTime, (int) availableSeconds);
//
//                   changeOvertTime-=processable;
//                    if(changeOvertTime>0)
//                    {
//                        shift.setUsed(true);
//                    }else {
//                        ScheduleResultDetail time =new ScheduleResultDetail();
//                        time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, shiftEnd.plusSeconds(-processable)));
//                        time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, shiftEnd));
//
//                        CopyOnWriteArrayList<TimeSegment> usedSegments1=  RemoveMachineAvailable(machine, time,shift);
//                        if (usedSegments1 != null && usedSegments1.size() > 0) {
//                            usedSegments.addAll(usedSegments1);
//                        }
//                    }
//                    if(i!=setuptime.size()-1)
//                    {
//                        TimeSegment shift2 = setuptime.get(i+1);
//                        LocalDateTime shiftEnd2 = shift2.getEnd();
//                        long availableSeconds2 = ChronoUnit.SECONDS.between(shiftEnd2, shiftStart);
//
//                        changeOvertTime-=availableSeconds2;
//                    }
//                   i++;
//               }
           }
            if(islockMachineTime) {
                if (usedSegments != null && usedSegments.size() > 0) {
                    machine.getAvailability().addAll(usedSegments);
                    machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
                }
            }

            times=  CaldScheduleResult(
                    machine, operation, processingTime,  startTime,
                    timeSegments, oneTime, quantity,islockMachineTime,isJit
            );

        }else {
            //换型时间在工作时间
            int i = 0;
            //要先把换型时间占用的工作时间占用
            LocalDateTime ChangeOverstartTime=startTime;
            LocalDateTime ChangeOverendTime=startTime;
            int changeOvertTimeold=changeOvertTime;
            while (changeOvertTime > 0) {
                TimeSegment shift = timeSegments.get(i);

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

                // 计算有效时间
                LocalDateTime effectiveStart = startTime.isAfter(shiftStart) ? startTime : shiftStart;
                long availableSeconds = ChronoUnit.SECONDS.between(effectiveStart, shiftEnd);

                // 处理当前班次
                int processable = Math.min(changeOvertTime, (int) availableSeconds);

                changeOvertTime -= processable;
                startTime = effectiveStart.plusSeconds(processable);
                ChangeOverendTime=startTime;
                ScheduleResultDetail time =new ScheduleResultDetail();
                time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
                time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, startTime));
                time.setChangeOverTime(true);
                if(islockMachineTime) {
                    CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time, shift, islockMachineTime);

                    if (usedSegments1 != null && usedSegments1.size() > 0) {
                        usedSegments.addAll(usedSegments1);
                    }
                }

                if(processable>=availableSeconds)
                {
                    i++;
                }

            }

             ChangeOverTimenew =(int)ChronoUnit.SECONDS.between(ChangeOverstartTime, ChangeOverendTime);


          //  processingTime=  processingTime-changeOvertTimeold;
            TimeSegment slot = timeSegments.get(i);

            LocalDateTime startCandidate = slot.getStart().isAfter(startTime)
                    ? slot.getStart()
                    :  startTime;


            // LocalDateTime endCandidate = startCandidate.plusSeconds(processingTime);
            long availableSeconds = ChronoUnit.SECONDS.between(startCandidate, slot.getEnd());
            //实际可用时间
            long availableSeconds_e =Math.round(availableSeconds*slot.getEfficiency()) ;



            //  if (endCandidate.isAfter(slot.getEnd())) {





                if (processingTime>availableSeconds_e) {
                CopyOnWriteArrayList<TimeSegment> timeSegments1=   timeSegments.stream()
                        .filter(t->t.getStart().compareTo(startCandidate)>=0)
                        .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
                times=  CaldScheduleResult(
                        machine, operation,  processingTime,  startTime,
                        timeSegments1, oneTime, quantity,islockMachineTime,isJit);
            } else {
               double e=  (double)processingTime/slot.getEfficiency();

               LocalDateTime endCandidate = startCandidate.plusSeconds((int)Math.ceil(e));

                ScheduleResultDetail time = new ScheduleResultDetail();
                time.setKey(slot.getKey());
                time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, startCandidate));
                time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, endCandidate));
                time.setOneTime(oneTime);
                time.setQuantity(quantity);
                times.add(time);

                    if(islockMachineTime) {
                        CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time, slot);
                        if (usedSegments1 != null && usedSegments1.size() > 0) {
                            usedSegments.addAll(usedSegments1);
                        }
                    }
            }
            if (usedSegments != null && usedSegments.size() > 0) {
                machine.getAvailability().addAll(usedSegments);
                machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
            }
        }
        result.put(1,ChangeOverTimenew);
        result.put(2,times);
        return result;
    }



    // 查找最早可用开始时间

    private CopyOnWriteArrayList<ScheduleResultDetail> findEarliestStart(
            Machine machine,Entry operation, int processingTime, LocalDateTime currentTime,
            String prevtime, CopyOnWriteArrayList<GAScheduleResult> existingTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
    ,boolean isInterrupt,boolean isJit) {
        CopyOnWriteArrayList<GAScheduleResult> machineTasks=null;
        if(existingTasks!=null&&existingTasks.size()>0) {
             machineTasks = existingTasks.stream()
                    .filter(t -> t.getMachineId() == machine.getId())
                    .sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        }

        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();

        if(operation.getQuantity()==0)
        {
            ScheduleResultDetail time = new ScheduleResultDetail();
            time.setKey("");
            time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
            time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
            time.setOneTime(oneTime);
            time.setQuantity(quantity);
            times.add(time);
            return times;
        }

        TimeSegment slot = GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime,isJit);
        if (slot == null)
        {
            return times;
        }
        LocalDateTime startCandidate=null;
        LocalDateTime endCandidate1= null;
        LocalDateTime prevTimeDateTime = StringUtils.isEmpty(prevtime) ? null : LocalDateTime.parse(prevtime);

        if(isJit)
        {
             startCandidate= slot.getStart();
            endCandidate1 = slot.getEnd().isAfter(prevTimeDateTime != null ? prevTimeDateTime : currentTime)
                    ? (prevTimeDateTime != null ? prevTimeDateTime : currentTime)
                    : slot.getEnd();

        }else {
             startCandidate = slot.getStart().isAfter(prevTimeDateTime != null ? prevTimeDateTime : currentTime)
                    ? slot.getStart()
                    : (prevTimeDateTime != null ? prevTimeDateTime : currentTime);

             endCandidate1 = slot.getEnd();
        }

       // LocalDateTime endCandidate = startCandidate.plusSeconds(processingTime);
        long availableSeconds = ChronoUnit.SECONDS.between(startCandidate, endCandidate1);
       //实际可用时间
        long availableSeconds_e =Math.round(availableSeconds*slot.getEfficiency()) ;



      //  if (endCandidate.isAfter(slot.getEnd())) {
        if (processingTime>availableSeconds_e) {
            return CaldEarliestStart(machine, operation, processingTime, currentTime, prevtime, machineTasks,oneTime,quantity, checkprevtime,islockMachineTime,isInterrupt,isJit);
        } else {


            double e=  (double)processingTime/slot.getEfficiency();
            LocalDateTime endCandidate=null;
            LocalDateTime startCandidate1 = null;
            if(isJit)
            {
                endCandidate = endCandidate1;
                startCandidate1=endCandidate.plusSeconds(-(int) Math.ceil(e));;
            }else {
                 endCandidate = startCandidate.plusSeconds((int) Math.ceil(e));
                startCandidate1=startCandidate;
            }

            ScheduleResultDetail time = new ScheduleResultDetail();
            time.setKey(slot.getKey());
            time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, startCandidate1));
            time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, endCandidate));
            time.setOneTime(oneTime);
            time.setQuantity(quantity);

            times.add(time);

            if(islockMachineTime) {
                CopyOnWriteArrayList<TimeSegment> usedSegments = RemoveMachineAvailable(machine, time, slot);
                if (usedSegments != null && usedSegments.size() > 0) {
                    machine.getAvailability().addAll(usedSegments);
                    machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
                }
            }
            return times;
        }
    }


    private List<ScheduleResultDetail> CaldEarliestStart1(
            Machine machine, int processingTime, LocalDateTime currentTime,
            String prevtime, List<GAScheduleResult> machineTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
    ) {
        int remainingTime = processingTime;
        LocalDateTime st = StringUtils.isEmpty(prevtime) ? currentTime : LocalDateTime.parse(prevtime);
        LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
        List<ScheduleResultDetail> times = new ArrayList<>();
        List<ScheduleResultDetail> oldTimes = new ArrayList<>();

        while (remainingTime > 0) {
            TimeSegment shift = GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime,false);
            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)) {
                    // 检查班次间任务

                 boolean  hasTask=  CheckTask( machine, machineTasks, prevEnd, shiftStart);

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



                }
            }

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

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

            // 添加时间详情
            ScheduleResultDetail time = new ScheduleResultDetail();
            time.setKey(shift.getKey());
            time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
            time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
            time.setQuantity((int)(processable/oneTime));
            time.setOneTime(oneTime);
            times.add(time);
            if (islockMachineTime) {
                // 还原未使用的时间段
                RemoveMachineAvailable(machine, time,shift);
            }

        }

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

    private CopyOnWriteArrayList<ScheduleResultDetail> CaldEarliestStart(
            Machine machine,Entry operation, int processingTime, LocalDateTime currentTime,
            String prevtime, CopyOnWriteArrayList<GAScheduleResult> machineTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
    ,boolean isInterrupt,boolean isJit) {
        int remainingTime = processingTime;
        LocalDateTime st = StringUtils.isEmpty(prevtime) ? currentTime : LocalDateTime.parse(prevtime);
        LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();

        CopyOnWriteArrayList<TimeSegment> timeSegments= findAvailableSegments(machine, currentTime, machineTasks, remainingTime, isInterrupt,isJit);
        if (timeSegments == null || timeSegments.isEmpty()) {
            return null;
        }
        times=  CaldScheduleResult(
                 machine, operation,  processingTime,  currentTime,
                 timeSegments, oneTime, quantity,islockMachineTime,isJit
            );

//        int estimateIndex= (int) Math.ceil(remainingTime / (double) ONE_DAY_MINUTES);
//        CopyOnWriteArrayList<TimeSegment> timeSegments1=null;
//        if(estimateIndex>10)
//       {
//            timeSegments1= getEnoughSegmentsByEstimateIndex(timeSegments,currentTime,remainingTime);
//        }
//
//        if(timeSegments1==null) {
//            int i = 0;
//            CopyOnWriteArrayList<TimeSegment> usedSegments =new CopyOnWriteArrayList<>();
//            while (remainingTime > 0) {
//                TimeSegment shift = timeSegments.get(i);
//
//                Map<Integer, Object> outMap = CreateScheduleResultDetail(shift, st, remainingTime, oneTime);
//                remainingTime = (int) outMap.get(1);
//                ScheduleResultDetail time = (ScheduleResultDetail) outMap.get(2);
//                times.add(time);
//                // 还原未使用的时间段
//                CopyOnWriteArrayList<TimeSegment> usedSegments1=   RemoveMachineAvailable(machine, time,shift);
//               if(usedSegments1!=null&&usedSegments1.size()>0)
//               {
//                   usedSegments.addAll(usedSegments1);
//               }
//                i++;
//            }
//
//            if (usedSegments != null && usedSegments.size() > 0) {
//                machine.getAvailability().addAll(usedSegments);
//                machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
//            }
//        }else {
//           times= CaldScheduleResultDetail(timeSegments1,machine,st,remainingTime,oneTime);
//        }

        return times;
    }

    private CopyOnWriteArrayList<ScheduleResultDetail> CaldScheduleResult(
            Machine machine,Entry operation, int processingTime, LocalDateTime currentTime,
            CopyOnWriteArrayList<TimeSegment> timeSegments,double oneTime,double quantity
            , boolean islockMachineTime,boolean isJit) {
        int remainingTime = processingTime;
        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();


        int estimateIndex= (int) Math.ceil(remainingTime / (double) ONE_DAY_MINUTES);
        CopyOnWriteArrayList<TimeSegment> timeSegments1=null;



        if(estimateIndex>10)
        {
            timeSegments1= getEnoughSegmentsByEstimateIndex(timeSegments,currentTime,remainingTime,isJit);

        }

        if(timeSegments1==null) {
            int i = 0;
            CopyOnWriteArrayList<TimeSegment> usedSegments =new CopyOnWriteArrayList<>();

            double AvTotal = calculateTotalMinutesByIndex(timeSegments, currentTime, timeSegments.size(), isJit);

            if(AvTotal<remainingTime)
            {

                return null;

            }

            while (remainingTime > 0) {



                TimeSegment shift = timeSegments.get(i);

                Map<Integer, Object> outMap = CreateScheduleResultDetail(shift, currentTime, remainingTime, oneTime,isJit);
                remainingTime = (int) outMap.get(1);
                ScheduleResultDetail time = (ScheduleResultDetail) outMap.get(2);
                times.add(time);
                // 还原未使用的时间段
                if(islockMachineTime) {
                    CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time, shift);
                    if (usedSegments1 != null && usedSegments1.size() > 0) {
                        usedSegments.addAll(usedSegments1);
                    }
                }
                i++;
            }

            if (usedSegments != null && usedSegments.size() > 0) {
                machine.getAvailability().addAll(usedSegments);
                machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
            }
        }else {
            times= CaldScheduleResultDetail(timeSegments1,machine, operation,currentTime,remainingTime,oneTime,islockMachineTime,isJit);
        }

        return times;
    }

    private CopyOnWriteArrayList<ScheduleResultDetail> CaldScheduleResultDetail(CopyOnWriteArrayList<TimeSegment> timeSegments,Machine machine,Entry operation,LocalDateTime st,int remainingTime,double oneTime,boolean islockMachineTime,boolean isJit)
    {

        int processable1 =(int)calculateTotalAvailableSecond(timeSegments, st,isJit);
        CopyOnWriteArrayList<TimeSegment> usedSegments =new CopyOnWriteArrayList<>();


        CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();

        //第一个数据
        TimeSegment  shiftfrist=  timeSegments.get(0);

        Map<Integer, Object> outMap= CreateScheduleResultDetail(shiftfrist,st,remainingTime,oneTime,isJit);
        remainingTime=(int)outMap.get(1);
        ScheduleResultDetail time1=(ScheduleResultDetail)outMap.get(2);
        times.add(time1);
        if(islockMachineTime) {
            CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time1, shiftfrist);
            if (usedSegments1 != null && usedSegments1.size() > 0) {
                usedSegments.addAll(usedSegments1);
            }
        }
        // 计算有效时间
//中间的数据
        CopyOnWriteArrayList<TimeSegment> timeSegments2= new CopyOnWriteArrayList<>(timeSegments.subList(1,timeSegments.size()-1));


        LocalDateTime effectiveStart=timeSegments2.get(0).getStart();
        LocalDateTime effectiveend=timeSegments2.get(timeSegments2.size()-1).getEnd();

        int processable =(int)calculateTotalAvailableSecond(timeSegments2, st,isJit);
        ScheduleResultDetail time = new ScheduleResultDetail();
        time.setKey(UUID.randomUUID().toString());
        time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
        time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveend));

        BigDecimal bd = new BigDecimal(String.valueOf(processable/oneTime));

        BigDecimal roundedBd = bd.setScale(4, RoundingMode.HALF_UP);

        time.setQuantity(roundedBd.doubleValue());


        time.setOneTime(oneTime);
        time.setUsedSegment(timeSegments2);
        if(islockMachineTime) {
            timeSegments2.forEach(t -> t.setUsed(true));
            remainingTime -= processable;
        }

        times.add(time);


//最后的时间段
        TimeSegment  shiftlast=  timeSegments.get(timeSegments.size()-1);

        Map<Integer, Object> outMaplast= CreateScheduleResultDetail(shiftlast,st,remainingTime,oneTime,isJit);
        remainingTime=(int)outMaplast.get(1);
        ScheduleResultDetail timelast=(ScheduleResultDetail)outMaplast.get(2);
        times.add(timelast);

        if(islockMachineTime) {
            CopyOnWriteArrayList<TimeSegment> usedSegments2 = RemoveMachineAvailable(machine, timelast, shiftlast);
            if (usedSegments2 != null && usedSegments2.size() > 0) {
                usedSegments.addAll(usedSegments2);
            }

            if (usedSegments != null && usedSegments.size() > 0) {
                machine.getAvailability().addAll(usedSegments);
                machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
            }
        }

        return times;
    }
    private Map<Integer, Object> CreateScheduleResultDetail(TimeSegment  shift,LocalDateTime st,int remainingTime,double oneTime,boolean isJit)
    {

        LocalDateTime shiftStart = shift.getStart();
        LocalDateTime shiftEnd = shift.getEnd();
        // 计算有效时间
        LocalDateTime effectiveStart = null;

        LocalDateTime effectiveEnd=null;
        if(isJit)
        {
            effectiveStart=shiftStart;
            effectiveEnd = st.isBefore(shiftEnd) ? st : shiftEnd;

        }else {
            // 计算有效时间
             effectiveStart = st.isAfter(shiftStart) ? st : shiftStart;

             effectiveEnd=shiftEnd;
        }




        long availableSeconds = ChronoUnit.SECONDS.between(effectiveStart, effectiveEnd);

        long availableSeconds_e =Math.round(availableSeconds*shift.getEfficiency()) ;

        // 处理当前班次
        int processable = Math.min(remainingTime, (int) availableSeconds_e);
        remainingTime -= processable;
      double e=  (double)availableSeconds/availableSeconds_e*processable;

        LocalDateTime currentTime = effectiveStart.plusSeconds((int)Math.ceil(e));

        // 添加时间详情
        ScheduleResultDetail time = new ScheduleResultDetail();
        time.setKey(shift.getKey());
       // time.setStartTime( (int)Duration.between(baseTime, effectiveStart).getSeconds());
       // time.setEndTime( (int)Duration.between(baseTime, currentTime).getSeconds());

        time.setStartTime(Math.abs ((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart)));
        time.setEndTime(Math.abs ((int) ChronoUnit.SECONDS.between(baseTime, currentTime)));
        time.setEfficiency(shift.getEfficiency());
        BigDecimal bd = new BigDecimal(String.valueOf(processable/oneTime));

        BigDecimal roundedBd = bd.setScale(4, RoundingMode.HALF_UP);

        time.setQuantity(roundedBd.doubleValue());
        time.setOneTime(oneTime);
        Map<Integer, Object> outMap=new HashMap<>();
        outMap.put(1, remainingTime);
        outMap.put(2, time);
        return outMap;
    }

    /**
     * 查找满足时长要求的无冲突可用时段
     * @param machine 设备
     * @param start 起始时间
     * @param machineTasks 设备已有任务
     * @param requiredMinutes 工单所需总时长（分钟）
     * @param requireContinuous 是否不可中断（true=不可中断）
     * @return 满足条件的可用片段列表
     */
    private CopyOnWriteArrayList<TimeSegment> findAvailableSegments(
            Machine machine,
            LocalDateTime start,
            CopyOnWriteArrayList<GAScheduleResult> machineTasks,
            double requiredMinutes,
            boolean requireContinuous) {

        return   findAvailableSegments(machine, start, machineTasks, requiredMinutes, requireContinuous,false);
    }

    /**
     * 查找满足时长要求的无冲突可用时段
     * @param machine 设备
     * @param start 起始时间
     * @param machineTasks 设备已有任务
     * @param requiredMinutes 工单所需总时长（分钟）
     * @param requireContinuous 是否不可中断（true=不可中断）
     * @return 满足条件的可用片段列表
     */
    private CopyOnWriteArrayList<TimeSegment> findAvailableSegments(
            Machine machine,
            LocalDateTime start,
            CopyOnWriteArrayList<GAScheduleResult> machineTasks,
            double requiredMinutes,
            boolean requireContinuous,boolean isJit) {
        List<TimeSegment> availableSegments = new ArrayList<>();
        LocalDateTime current = start;

        // 预先排序设备可用片段，避免后续遍历混乱
//        List<TimeSegment> allUseTimeSegment = machine.getAvailability().stream()
//                .filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
//                .sorted(Comparator.comparing(TimeSegment::getStart, (a, b) -> a.compareTo(b)))
//                .collect(Collectors.toList());

        // 替换while(true)，增加明确退出条件（原逻辑保留，可根据业务补充退出判断）
        while (true) {
            // 统一过滤逻辑：消除重复的FindAll代码
            CopyOnWriteArrayList<TimeSegment> useSegments = filterValidUseSegments(machine.getAvailability(), current, requireContinuous, requiredMinutes,isJit);

            if (useSegments != null && !useSegments.isEmpty()) {
                // 计算可用时间总和（保留原有逻辑）
                double totalUseTime = calculateTotalAvailableSecond(useSegments, current,isJit);

                //倒排，可用时间不够，应该重新正排
                if(totalUseTime < requiredMinutes&&isJit)
                {
                    return null;
                }

                // 不足所需时长时，自动生成未来片段并补充
                while (totalUseTime < requiredMinutes) {
                    // 生成未来1天的片段（基于当前可用片段的最大结束时间）
                    LocalDateTime lastSegmentEnd = machine.getAvailability().stream()
                            .max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                            .map(TimeSegment::getEnd)
                            .orElse(current);
                    int days=((int) ((requiredMinutes-totalUseTime)/24/3600));
                    if(days<=200)
                    {
                        days=0;
                    }
                    CopyOnWriteArrayList<TimeSegment> newSegments = machineScheduler.generateTimeSegment(machine, lastSegmentEnd.plusDays(1),days);
                    addSegmentsWithDeduplication(machine, newSegments);


                    // 重新过滤可用片段
                    useSegments = filterValidUseSegments(machine.getAvailability(), current, requireContinuous, requiredMinutes);
                    // 重新计算总可用时间
                    totalUseTime = calculateTotalAvailableSecond(useSegments, current,isJit);
                }

                // 若总可用时间满足要求，处理冲突
                if (totalUseTime >= requiredMinutes) {
                    // 获取当前可用片段范围内的冲突
                    LocalDateTime firstSegmentStart = useSegments.get(0).getStart().compareTo(current) < 0?current:useSegments.get(0).getStart();
                    LocalDateTime lastSegmentEnd = useSegments.get(useSegments.size() - 1).getEnd();
                   //获取维修和当前任务
                    CopyOnWriteArrayList<TimeSegment> conflictSegments = getConflictIntervals(machine, machineTasks, firstSegmentStart, lastSegmentEnd);

                    if (conflictSegments == null || conflictSegments.isEmpty()) {
                        // 无冲突：直接返回可用片段（保留原有逻辑）
                        if(isJit)
                        {
                            if (useSegments.get(0).getEnd().compareTo(current) > 0) {
                                spiltMachineAvailable(machine, useSegments.get(0), current,isJit);
                                useSegments.get(0).setEnd(current);
                            }
                        }
                        else {
                            if (useSegments.get(0).getStart().compareTo(current) < 0) {
                                spiltMachineAvailable(machine, useSegments.get(0), current,isJit);
                                useSegments.get(0).setStart(current);
                            }
                        }
                        return useSegments;
                    } else {
                        // 有冲突：可选返回冲突前足够片段或跳过冲突
                        CopyOnWriteArrayList<TimeSegment> resultSegments = handleConflictsWithSumLogic(useSegments, conflictSegments, current, requiredMinutes,isJit);
                        if (resultSegments != null && !resultSegments.isEmpty()) {
                            if(isJit)
                            {
                                if (resultSegments.get(0).getEnd().compareTo(current) > 0) {
                                    spiltMachineAvailable(machine, resultSegments.get(0), current, isJit);
                                    resultSegments.get(0).setEnd(current);
                                }

                            }
                            else {
                                if (resultSegments.get(0).getStart().compareTo(current) < 0) {
                                    spiltMachineAvailable(machine, resultSegments.get(0), current, isJit);
                                    resultSegments.get(0).setStart(current);
                                }
                            }
                            return resultSegments;
                        } else {
                            // 冲突前片段不足，重置current为最后一个冲突的结束时间，重新查找
                            if(isJit) {
                                LocalDateTime lastConflictEnd = conflictSegments.stream()
                                        .min(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                                        .map(TimeSegment::getStart)
                                        .orElse(current);
                                current = lastConflictEnd;
                            }else {
                                LocalDateTime lastConflictEnd = conflictSegments.stream()
                                        .max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                                        .map(TimeSegment::getEnd)
                                        .orElse(current);
                                current = lastConflictEnd;
                            }
                        }
                    }
                }
            } else {

                if(isJit)
                {
                    return null;
                }
                // 无可用片段时，生成未来1天的片段
                LocalDateTime lastSegmentEnd = machine.getAvailability().stream()
                        .max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                        .map(TimeSegment::getEnd)
                        .orElse(current);



                CopyOnWriteArrayList<TimeSegment> newSegments = machineScheduler.generateTimeSegment(machine, lastSegmentEnd.plusDays(1),0);
                addSegmentsWithDeduplication(machine, newSegments);
            }
        }
    }


    /**
     * 查找满足时长要求的无冲突可用时段
     * @param machine 设备
     * @param start 起始时间
     * @param machineTasks 设备已有任务
     * @param requiredMinutes 工单所需总时长（分钟）
     * @param requireContinuous 是否不可中断（true=不可中断）
     * @return 满足条件的可用片段列表
     */
    private CopyOnWriteArrayList<TimeSegment> findAvailableSegments(
            Machine machine,
            LocalDateTime start,
            LocalDateTime end,
            CopyOnWriteArrayList<GAScheduleResult> machineTasks,
            double requiredMinutes,
            boolean requireContinuous,boolean isJit) {
        List<TimeSegment> availableSegments = new ArrayList<>();
        LocalDateTime current = start;

        // 预先排序设备可用片段，避免后续遍历混乱
//        List<TimeSegment> allUseTimeSegment = machine.getAvailability().stream()
//                .filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
//                .sorted(Comparator.comparing(TimeSegment::getStart, (a, b) -> a.compareTo(b)))
//                .collect(Collectors.toList());

        // 替换while(true)，增加明确退出条件（原逻辑保留，可根据业务补充退出判断）
        while (true) {
            // 统一过滤逻辑：消除重复的FindAll代码
            CopyOnWriteArrayList<TimeSegment> useSegments = filterValidUseSegments(machine.getAvailability(), current, requireContinuous, requiredMinutes);

            if (useSegments != null && !useSegments.isEmpty()) {
                // 计算可用时间总和（保留原有逻辑）
                double totalUseTime = calculateTotalAvailableSecond(useSegments, current,isJit);

                // 不足所需时长时，自动生成未来片段并补充
                while (totalUseTime < requiredMinutes) {
                    // 生成未来1天的片段（基于当前可用片段的最大结束时间）
                    LocalDateTime lastSegmentEnd = machine.getAvailability().stream()
                            .max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                            .map(TimeSegment::getEnd)
                            .orElse(current);
                    int days=((int) ((requiredMinutes-totalUseTime)/24/3600));
                    if(days<=200)
                    {
                        days=0;
                    }
                    CopyOnWriteArrayList<TimeSegment> newSegments = machineScheduler.generateTimeSegment(machine, lastSegmentEnd.plusDays(1),days);
                    addSegmentsWithDeduplication(machine, newSegments);


                    // 重新过滤可用片段
                    useSegments = filterValidUseSegments(machine.getAvailability(), current, requireContinuous, requiredMinutes);
                    // 重新计算总可用时间
                    totalUseTime = calculateTotalAvailableSecond(useSegments, current,isJit);
                }

                // 若总可用时间满足要求，处理冲突
                if (totalUseTime >= requiredMinutes) {
                    // 获取当前可用片段范围内的冲突
                    LocalDateTime firstSegmentStart = useSegments.get(0).getStart().compareTo(current) < 0?current:useSegments.get(0).getStart();
                    LocalDateTime lastSegmentEnd = useSegments.get(useSegments.size() - 1).getEnd();
                    //获取维修和当前任务
                    CopyOnWriteArrayList<TimeSegment> conflictSegments = getConflictIntervals(machine, machineTasks, firstSegmentStart, lastSegmentEnd);

                    if (conflictSegments == null || conflictSegments.isEmpty()) {
                        // 无冲突：直接返回可用片段（保留原有逻辑）
                        if (useSegments.get(0).getStart().compareTo(current) < 0) {
                            spiltMachineAvailable(machine, useSegments.get(0), current,isJit);
                            useSegments.get(0).setStart(current);
                        }
                        return useSegments;
                    } else {
                        // 有冲突：可选返回冲突前足够片段或跳过冲突
                        CopyOnWriteArrayList<TimeSegment> resultSegments = handleConflictsWithSumLogic(useSegments, conflictSegments, current, requiredMinutes,isJit);
                        if (resultSegments != null && !resultSegments.isEmpty()) {
                            if (resultSegments.get(0).getStart().compareTo(current) < 0) {
                                spiltMachineAvailable(machine, resultSegments.get(0), current,isJit);
                                resultSegments.get(0).setStart(current);
                            }
                            return resultSegments;
                        } else {
                            // 冲突前片段不足，重置current为最后一个冲突的结束时间，重新查找
                            LocalDateTime lastConflictEnd = conflictSegments.stream()
                                    .max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                                    .map(TimeSegment::getEnd)
                                    .orElse(current);
                            current = lastConflictEnd;
                        }
                    }
                }
            } else {
                // 无可用片段时，生成未来1天的片段
                LocalDateTime lastSegmentEnd = machine.getAvailability().stream()
                        .max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
                        .map(TimeSegment::getEnd)
                        .orElse(current);
                CopyOnWriteArrayList<TimeSegment> newSegments = machineScheduler.generateTimeSegment(machine, lastSegmentEnd.plusDays(1),0);
                addSegmentsWithDeduplication(machine, newSegments);
            }
        }
    }



    private static final int ONE_DAY_MINUTES = 24 * 60*60; // 固定锚点：一天1440分钟，永不改变

    /**
     * 按预估索引快速获取满足时长的时段数组
     * @param availableSegments 有序的可用时段列表（必须按Start升序，业务中天然满足）
     * @param currentTime 排程开始时间
     * @param requiredMinutes 需要的总分钟数（支持超大值：几万/几十万分钟）
     * @return 刚好满足时长的片段数组
     * @throws IllegalArgumentException 总时长不足时抛出
     */
    public CopyOnWriteArrayList<TimeSegment> getEnoughSegmentsByEstimateIndex(
            CopyOnWriteArrayList<TimeSegment> availableSegments,
            LocalDateTime currentTime,
            int requiredMinutes,boolean isJit) {
        // 基础校验
        if (availableSegments == null || availableSegments.isEmpty()) {
            throw new IllegalArgumentException("可用时段列表不能为空");
        }
        if (requiredMinutes <= 0) {
            return null;
        }

        int totalSegmentCount = availableSegments.size();

        // ========== 步骤1：核心！快速预估索引，一步到位，跳过几千个片段 ==========
        // 预估逻辑：需求时长/每天分钟数 + 5（冗余值，防止预估不足，可根据业务调整，实际班次不是24小时）,
        int estimateIndex= (int) Math.ceil(requiredMinutes / (double) ONE_DAY_MINUTES);

         estimateIndex =estimateIndex  + 5;
        // 边界保护：预估索引不能超过总片段数，也不能小于0
        estimateIndex = Math.min(estimateIndex, totalSegmentCount - 1);
        estimateIndex = Math.max(estimateIndex, 0);

        // ========== 步骤2：双向逼近，小范围循环增减索引，循环次数≤20次 ==========
        int targetIndex = estimateIndex;
        while (true) {
            // 计算当前索引的总有效时长
            double currentTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex, isJit);

            if (currentTotal >= requiredMinutes) {

                //  总时长满足，尝试往前减索引，找「最小满足索引」（减少后续裁剪的工作量）
                if (targetIndex > 0) {
                    double prevTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex - 1, isJit);
                    if (prevTotal >= requiredMinutes) {
                        targetIndex--;
                        continue;
                    }
                }
                break; // 找到最小满足索引，退出循环
            } else {

               double syday= (int)Math.ceil((requiredMinutes-currentTotal)/(double) ONE_DAY_MINUTES);

                //  总时长不足，往后加索引（每次加5，大步前进，加快逼近速度）
                targetIndex +=Math.max(syday, 5);
                if (targetIndex >= totalSegmentCount) {
                    // 所有片段总时长不足，抛出异常
                    double allTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, totalSegmentCount - 1, isJit);

                    if(allTotal>requiredMinutes)
                    {
                        double prevTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex - 1, isJit);
                        if (prevTotal >= requiredMinutes) {
                            targetIndex--;
                            continue;
                        }
                       break;
                    }
                    else if(allTotal==requiredMinutes)
                    {
                        return availableSegments;
                    }else {
                        return  null;
                    }
                }
            }
        }

        // ========== 步骤3：精准裁剪片段，返回最终结果 ==========
        CopyOnWriteArrayList<TimeSegment> resultList =new CopyOnWriteArrayList<>(availableSegments.subList(0,targetIndex)) ;
        return resultList;
    }

    /**
     * 计算从0到指定索引的所有时段的总有效分钟数
     */
    private double calculateTotalMinutesByIndex(CopyOnWriteArrayList<TimeSegment> segments, LocalDateTime currentTime, int endIndex,boolean isJit) {



        return   calculateTotalAvailableSecond(new  CopyOnWriteArrayList(segments.subList(0, endIndex)), currentTime, isJit);

    }
    /**
     * 统一过滤有效可用片段
     */
    private CopyOnWriteArrayList<TimeSegment> filterValidUseSegments(CopyOnWriteArrayList<TimeSegment> allSegments,
                                                                     LocalDateTime currentTime,
                                                                     boolean requireContinuous,
                                                                     double requiredMinutes) {
    return filterValidUseSegments( allSegments,
             currentTime,
         requireContinuous,
         requiredMinutes,false);
    }
    /**
     * 统一过滤有效可用片段
     */
    private CopyOnWriteArrayList<TimeSegment> filterValidUseSegments(CopyOnWriteArrayList<TimeSegment> allSegments,
                                                     LocalDateTime currentTime,
                                                     boolean requireContinuous,
                                                     double requiredMinutes,boolean isJit) {
        // 空判断
        if (allSegments == null || allSegments.isEmpty()) {
            return new CopyOnWriteArrayList<>();
        }

        // 统一过滤条件
        CopyOnWriteArrayList<TimeSegment> baseValidSegments=new CopyOnWriteArrayList<>();

        if(isJit)
        {
             baseValidSegments = allSegments.stream()
                    .filter(slot -> !slot.isUsed()  // 对应 !slot.IsUsed
                            && slot.getType() != SegmentType.MAINTENANCE  // 对应 slot.Type != SegmentType.Maintenance
                            && slot.getStart().compareTo(currentTime) < 0)
                     .sorted(Comparator.comparing(TimeSegment::getEnd).reversed()) // 对应 slot.End > currentTime
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));


        }else {
            baseValidSegments = allSegments.stream()
                    .filter(slot -> !slot.isUsed()  // 对应 !slot.IsUsed
                            && slot.getType() != SegmentType.MAINTENANCE  // 对应 slot.Type != SegmentType.Maintenance
                            && slot.getEnd().compareTo(currentTime) > 0)  // 对应 slot.End > currentTime
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        }
        // 无需不可中断或所需时长无效时，直接返回基础有效片段
        if (!requireContinuous || requiredMinutes <= 0) {
            return baseValidSegments;
        }
        //不可中断，中间不能休息
        if(isJit)
        {

            return filterContinuousCompliantSegmentsJit(baseValidSegments, currentTime, requiredMinutes);

        }
        // 要求不可中断时，过滤符合连续时长要求的片段
        return filterContinuousCompliantSegments(baseValidSegments, currentTime, requiredMinutes);
    }

    /**
     * 计算可用片段的总有效时长
     * @param useSegments 可用片段列表
     * @param currentTime 当前时间
     * @return 总可用时长（分钟）
     */
    private double calculateTotalAvailableSecond(CopyOnWriteArrayList<TimeSegment> useSegments, LocalDateTime currentTime,boolean isJit) {
        // 空判断：
        if (useSegments == null || useSegments.size()==0) {
            return 0.0;
        }

        if(isJit)
        {
            return useSegments.stream()
                    .mapToDouble(segment -> {
                        // 取片段起始时间和当前时间的最大值，t.End > currentTime ? t.End : currentTime
                        LocalDateTime effectiveend = segment.getEnd().compareTo(currentTime) > 0 ? currentTime :segment.getEnd() ;
                        // 计算单个片段的有效时长（分钟），并乘以效率值，对应C#的 (t.End - effectiveStart).TotalMinutes * t.Efficiency
                        double segmentSeconds =ChronoUnit.SECONDS.between(segment.getStart(), effectiveend);
                        return segmentSeconds * segment.getEfficiency();
                    })
                    .sum(); // 累加所有片段的有效时长
        }else {
            return useSegments.stream()
                    .mapToDouble(segment -> {
                        // 取片段起始时间和当前时间的最大值，t.Start < currentTime ? currentTime : t.Start
                        LocalDateTime effectiveStart = segment.getStart().compareTo(currentTime) < 0 ? currentTime : segment.getStart();
                        // 计算单个片段的有效时长（分钟），并乘以效率值，对应C#的 (t.End - effectiveStart).TotalMinutes * t.Efficiency
                        double segmentSeconds =ChronoUnit.SECONDS.between(effectiveStart, segment.getEnd());
                        return segmentSeconds * segment.getEfficiency();
                    })
                    .sum(); // 累加所有片段的有效时长
        }

    }

    /**
     * 计算可用片段在指定时间范围内的总有效时长（考虑效率系数）
     * @param useSegments 可用片段列表
     * @param startTime 起始时间（包含）
     * @param endTime 结束时间（包含，可为空表示无上限）
     * @return 总可用时长（分钟）
     */
    private double calculateTotalAvailableSecond(CopyOnWriteArrayList<TimeSegment> useSegments, LocalDateTime startTime, LocalDateTime endTime) {
        // 空判断：
        if (useSegments == null || useSegments.size()==0) {
            return 0.0;
        }

        return useSegments.stream()
                .mapToDouble(segment -> {
                    // 计算有效的起始时间：取 segment.start 和 startTime 的最大值
                    LocalDateTime effectiveStart = segment.getStart().compareTo(startTime) < 0 ? startTime : segment.getStart();

                    // 计算有效的结束时间：取 segment.end 和 endTime 的最小值（如果 endTime 为空，就用 segment.end）
                    LocalDateTime effectiveEnd = endTime != null ?
                            (segment.getEnd().compareTo(endTime) > 0 ? endTime : segment.getEnd())
                            : segment.getEnd();

                    // 如果有效的起始时间 >= 有效的结束时间，这个片段在范围内没有可用时间
                    if (effectiveStart.compareTo(effectiveEnd) >= 0) {
                        return 0.0;
                    }

                    // 计算单个片段的有效时长（秒），并乘以效率值
                    double segmentSeconds = ChronoUnit.SECONDS.between(effectiveStart, effectiveEnd);
                    return segmentSeconds * segment.getEfficiency();
                })
                .sum(); // 累加所有片段的有效时长
    }

    /**
     * 辅助方法：过滤出满足连续时长要求的片段（仅不可中断配置生效时调用）
     * 前置剔除零散无效片段，减少后续逻辑处理量
     */
    private CopyOnWriteArrayList<TimeSegment> filterContinuousCompliantSegments(
            CopyOnWriteArrayList<TimeSegment> baseValidSegments,
            LocalDateTime currentTime,
            double requiredContinuous) {
        // 空判断
        if (baseValidSegments == null || baseValidSegments.isEmpty()) {
            return new CopyOnWriteArrayList<>();
        }

        CopyOnWriteArrayList<TimeSegment> continuousCompliantSegments = new CopyOnWriteArrayList<>();
        CopyOnWriteArrayList<TimeSegment> tempContinuousGroup = new CopyOnWriteArrayList<>();
        double tempContinuous = 0.0;
        LocalDateTime lastSegmentEnd = currentTime;

        // 遍历基础有效片段，筛选出可拼接成连续时长的片段组
        for (TimeSegment segment : baseValidSegments) {
            // 确定有效起始时间：
            LocalDateTime effectiveStart = segment.getStart().compareTo(currentTime) > 0 ? segment.getStart() : currentTime;

            if (effectiveStart.compareTo(segment.getEnd()) >= 0) {
                // 该片段无有效时长，跳过
                continue;
            }

            // 判断是否与临时连续组无缝衔接
            if (!tempContinuousGroup.isEmpty() && effectiveStart.compareTo(lastSegmentEnd) != 0) {
                // 不衔接：先判断临时组是否满足连续时长，满足则加入结果
                if (tempContinuous >= requiredContinuous) {
                    continuousCompliantSegments.addAll(tempContinuousGroup);
                }
                // 重置临时组
                tempContinuousGroup.clear();
                tempContinuous = 0.0;
            }

            // 加入临时连续组，累加时长
            tempContinuousGroup.add(segment);

            // 计算当前片段有效时长（分钟）并累加
            double segmentEffective = ChronoUnit.SECONDS.between(effectiveStart, segment.getEnd()) * segment.getEfficiency();
            tempContinuous += segmentEffective;
            // 更新最后一个片段结束时间（加1秒）
            lastSegmentEnd = segment.getEnd().plusSeconds(1);

            // 临时组满足连续时长，直接加入结果（提前终止当前组遍历）
            if (tempContinuous >= requiredContinuous) {
                continuousCompliantSegments.addAll(tempContinuousGroup);
                // 可选择是否继续遍历（此处继续，获取所有符合条件的片段；也可break直接返回第一个组）
                tempContinuousGroup.clear();
                tempContinuous = 0.0;
            }
        }

        // 遍历结束后，检查最后一个临时组是否满足连续时长
        if (tempContinuous >= requiredContinuous) {
            continuousCompliantSegments.addAll(tempContinuousGroup);
        }

        // 去重并排序（避免重复片段）
        return MergeSegments(continuousCompliantSegments,false);
    }

    /**
     * 辅助方法：过滤出满足连续时长要求的片段（仅不可中断配置生效时调用）
     * 前置剔除零散无效片段，减少后续逻辑处理量
     */
    private CopyOnWriteArrayList<TimeSegment> filterContinuousCompliantSegmentsJit(
            CopyOnWriteArrayList<TimeSegment> baseValidSegments,
            LocalDateTime currentTime,
            double requiredContinuous) {
        // 空判断
        if (baseValidSegments == null || baseValidSegments.isEmpty()) {
            return new CopyOnWriteArrayList<>();
        }

        CopyOnWriteArrayList<TimeSegment> continuousCompliantSegments = new CopyOnWriteArrayList<>();
        CopyOnWriteArrayList<TimeSegment> tempContinuousGroup = new CopyOnWriteArrayList<>();
        double tempContinuous = 0.0;
        LocalDateTime lastSegmentStart = currentTime;


       // baseValidSegments.sort(Comparator.comparing(TimeSegment::getEnd).reversed());
        // 遍历基础有效片段，筛选出可拼接成连续时长的片段组
        for (TimeSegment segment : baseValidSegments) {
            // 确定有效起始时间：
            LocalDateTime effectiveEnd = segment.getEnd().compareTo(currentTime) > 0 ?currentTime  : segment.getEnd();

            if (effectiveEnd.compareTo(segment.getStart()) <= 0) {
                // 该片段无有效时长，跳过,结束时间跑到了开始时间的前面，所以没有可用时长
                continue;
            }

            // 判断是否与临时连续组无缝衔接
            if (!tempContinuousGroup.isEmpty() && effectiveEnd.compareTo(lastSegmentStart) != 0) {
                // 不衔接：先判断临时组是否满足连续时长，满足则加入结果
                if (tempContinuous >= requiredContinuous) {
                    continuousCompliantSegments.addAll(tempContinuousGroup);
                }
                // 重置临时组
                tempContinuousGroup.clear();
                tempContinuous = 0.0;
            }

            // 加入临时连续组，累加时长
            tempContinuousGroup.add(segment);

            // 计算当前片段有效时长（分钟）并累加
            double segmentEffective = ChronoUnit.SECONDS.between(segment.getStart(),effectiveEnd ) * segment.getEfficiency();
            tempContinuous += segmentEffective;
            // 更新最后一个片段开始时间（-1秒）
            lastSegmentStart = segment.getStart().plusSeconds(-1);

            // 临时组满足连续时长，直接加入结果（提前终止当前组遍历）
            if (tempContinuous >= requiredContinuous) {
                continuousCompliantSegments.addAll(tempContinuousGroup);
                // 可选择是否继续遍历（此处继续，获取所有符合条件的片段；也可break直接返回第一个组）
                tempContinuousGroup.clear();
                tempContinuous = 0.0;
            }
        }

        // 遍历结束后，检查最后一个临时组是否满足连续时长
        if (tempContinuous >= requiredContinuous) {
            continuousCompliantSegments.addAll(tempContinuousGroup);
        }

        // 去重并排序（避免重复片段）
        return MergeSegments(continuousCompliantSegments,true);
    }

    /**
     * 批量获取冲突区间（优化边界判断，更严谨）
     * 依赖：Machine、ScheduleResult、TimeSegment、DateTime 类（已在前序代码中定义，需补充部分属性）
     */
    private CopyOnWriteArrayList<TimeSegment> getConflictIntervals(
            Machine machine,
            CopyOnWriteArrayList<GAScheduleResult> machineTasks,
            LocalDateTime start,
            LocalDateTime end) {
        CopyOnWriteArrayList<TimeSegment> conflictIntervals = new CopyOnWriteArrayList<>();




        // 1. 维护窗口冲突（优化重叠判断，更严谨）
        if (machine.getMaintenanceWindows() != null && !machine.getMaintenanceWindows().isEmpty()) {
            // 过滤重叠的维护窗口并转换为TimeSegment
            CopyOnWriteArrayList<TimeSegment> maintenanceConflicts = machine.getMaintenanceWindows().stream()
                    // 正确的重叠判断：w.StartTime < end && w.EndTime > start
                    .filter(w -> w.getStartTime().compareTo(end) < 0 && w.getEndTime().compareTo(start) > 0)
                    // 转换为TimeSegment对象
                    .map(w -> new TimeSegment(w.getStartTime(), w.getEndTime()))
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
            // 批量添加冲突片段
            conflictIntervals.addAll(maintenanceConflicts);
        }

        // 2. 已有任务冲突
        if (machineTasks != null && machineTasks.size()>0) {
            // 第一步：转换任务为TimeSegment并过滤重叠冲突
            List<TimeSegment> taskConflicts = machineTasks.stream()
                    .map(w -> {
                        // 计算任务起始和结束时间：baseTime.AddMinutes(w.StartTime)/w.EndTime
                        LocalDateTime taskStart = baseTime.plusSeconds(w.getStartTime());
                        LocalDateTime taskEnd = baseTime.plusSeconds(w.getEndTime());
                        return new TimeSegment(taskStart, taskEnd);
                    })
                    // 正确的重叠判断：t.Start < end && t.End > start
                    .filter(t -> t.getStart().compareTo(end) < 0 && t.getEnd().compareTo(start) > 0)
                    .collect(Collectors.toList());



            // 批量添加任务冲突片段
            conflictIntervals.addAll(taskConflicts);
        }

        // 按开始时间排序
        return conflictIntervals.stream()
                .sorted(Comparator.comparing(TimeSegment::getStart, Comparator.nullsLast(LocalDateTime::compareTo)))
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
    }
    /**
     * 按总和逻辑处理冲突（保留原有冲突处理逻辑，优化严谨性）
     * @param useSegments 可用片段列表
     * @param conflictSegments 冲突片段列表
     * @param currentTime 当前时间
     * @param requiredMinutes 所需总时长（分钟）
     * @return 满足条件的片段列表，无满足条件时返回null
     */
    private CopyOnWriteArrayList<TimeSegment> handleConflictsWithSumLogic(
            CopyOnWriteArrayList<TimeSegment> useSegments,
            CopyOnWriteArrayList<TimeSegment> conflictSegments,
            LocalDateTime currentTime,
            double requiredMinutes,boolean isJit) {

        if(isJit)
        {
            // 将冲突片段按结束时间倒序排序（优先处理结束时间晚的冲突）
            CopyOnWriteArrayList<TimeSegment> sortedConflicts = new CopyOnWriteArrayList<>(conflictSegments);
            sortedConflicts.sort((a, b) -> b.getEnd().compareTo(a.getEnd()));

            for (TimeSegment conflict : sortedConflicts) {
                LocalDateTime currentTime1 = currentTime;

                //需要获取从conflict.getEnd() 到 currentTime1的
                   CopyOnWriteArrayList<TimeSegment> preConflictSegments = useSegments.stream()
                        .filter(slot -> {
                            // 情况1: 整个片段完全在 [conflict.getEnd(), currentTime1] 之间
                            if (slot.getStart().isAfter(conflict.getEnd()) && slot.getEnd().isBefore(currentTime1)) {
                                return true;
                            }
                            // 情况2: 片段的开始在 currentTime1 之前，但结束在 currentTime1 之后（右端重叠）
                            if (slot.getStart().isAfter(conflict.getEnd()) && slot.getStart().isBefore(currentTime1) && slot.getEnd().isAfter(currentTime1)) {
                                return true;
                            }
                            // 情况3: 片段的开始在 conflict.getEnd() 之前，但结束在 conflict.getEnd() 之后（左端重叠）
                            if (slot.getStart().isBefore(conflict.getEnd()) && slot.getEnd().isAfter(conflict.getEnd()) && slot.getEnd().isBefore(currentTime1)) {
                                return true;
                            }
                            // 情况4: 片段完全包含整个 [conflict.getEnd(), currentTime1] 范围
                            if (slot.getStart().isBefore(conflict.getEnd()) && slot.getEnd().isAfter(currentTime1)) {
                                return true;
                            }
                            return false;
                        })
                        .collect(Collectors.toCollection(CopyOnWriteArrayList::new));

                // 计算冲突后片段的总可用时长
                double preConflictTotalTime = calculateTotalAvailableSecond(preConflictSegments,conflict.getEnd(), currentTime1);

                // 冲突后时长超过所需时长则返回（保留原有判断逻辑），否则更新当前时间跳过冲突
                if (preConflictTotalTime > requiredMinutes) {
                    return preConflictSegments;
                } else {
                    //更新当前时间为冲突开始时间-1秒
                    currentTime = conflict.getStart().plusSeconds(-1);
                }
            }
        }
        else {
            // 遍历所有冲突片段
            for (TimeSegment conflict : conflictSegments) {
                LocalDateTime currentTime1 = currentTime;
                // 过滤冲突前的可用片段（
                CopyOnWriteArrayList<TimeSegment> preConflictSegments = useSegments.stream()
                        .filter(slot ->
                                (slot.getStart().compareTo(currentTime1) >= 0 || slot.getEnd().compareTo(currentTime1) > 0)
                                        && slot.getEnd().compareTo(conflict.getStart()) <= 0
                        )
                        .collect(Collectors.toCollection(CopyOnWriteArrayList::new));

                // 计算冲突前片段的总可用时长
                double preConflictTotalTime = calculateTotalAvailableSecond(preConflictSegments, currentTime,isJit);

                // 冲突前时长超过所需时长则返回（保留原有判断逻辑），否则更新当前时间跳过冲突
                if (preConflictTotalTime > requiredMinutes) {
                    return preConflictSegments;
                } else {
                    //更新当前时间为冲突结束时间+1秒
                    currentTime = conflict.getEnd().plusSeconds(1);
                }
            }
        }

        // 所有冲突前片段均不足所需时长，返回null（与原C#逻辑一致）
        return null;
    }
    /**
     * 追加片段并去重、排序（避免冗余片段和遍历混乱）
     */
    private void addSegmentsWithDeduplication(Machine machine, CopyOnWriteArrayList<TimeSegment> newSegments) {
        // 空判断：新片段为null或空集合时直接返回，对应C#的 newSegments == null || newSegments.Count == 0
        if (newSegments == null || newSegments.isEmpty()) {
            return;
        }

        machine.getAvailability().addAll(newSegments);
        CopyOnWriteArrayList<TimeSegment> mergedSegments = MergeSegments(machine.getAvailability(),false);

       // synchronized (machine.getAvailability()) {
            // 合并片段（去重+排序），
            machine.setAvailability(mergedSegments);
       // }



    }

    private boolean CheckTask(Machine machine,List<GAScheduleResult> machineTasks,LocalDateTime prevEnd,LocalDateTime shiftStart) {
        LocalDateTime finalPrevEnd = prevEnd;
        boolean hasTask = machineTasks.stream()
                .anyMatch(t -> {
                    LocalDateTime taskStart = baseTime.plusSeconds(t.getStartTime());
                    return taskStart.isAfter(finalPrevEnd) && taskStart.isBefore(shiftStart);
                });

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

                return hasMaintenance;
            }
        }
        return hasTask;
    }

    /**
     * 获取设备当前或下一个有效班次
     */
    public TimeSegment GetCurrentOrNextShift(Machine machine, LocalDateTime time, String prevtime, boolean checkprevtime,boolean isJit) {
        TimeSegment start = null;

        if(isJit)
        {
            if (!machine.getAvailability().isEmpty())
            {
                LocalDateTime machineValidTo=  machineScheduler.GetEndTime(machine.getId());
                if(machineValidTo.compareTo(time)<0)
                {


                    int day = (int) ChronoUnit.DAYS.between(machineValidTo, time);

                    List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, machineValidTo.plusDays(1), day);


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

                start = machine.getAvailability().stream()
                        .filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
                        .filter(slot -> slot.getStart().compareTo(time)<0)
                        .reduce((prev, current) -> current)
                        .orElse(null); // 没有符合条件的元素时返回null
                if (start == null) {
                    //倒排，没有可用时间
                    return null;
                }
            }
        }else {

            if (!machine.getAvailability().isEmpty()) {
                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);
            } else {
                machine.setAvailability(new CopyOnWriteArrayList<>());
            }
            // 查找有效班次


            if (start == null) {
                // 生成新时间段
                List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, time.plusDays(1), 0);


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

        return start;
    }

    /**
     * 检查设备的可用开工时间
     * @param machine 目标设备
     * @param processingTime 加工时长（分钟）
     * @param currentTime 当前时间
     * @param startTime 开始时间
     * @param existingTasks 已有任务列表
     * @return 可用时间段列表，无可用时间返回null
     */
    public List<ScheduleResultDetail> checkMachineStartTime(Machine machine, int processingTime,
                                                   LocalDateTime currentTime, LocalDateTime startTime,
                                                   List<GAScheduleResult> existingTasks) {
        // 获取设备上已有任务并按开始时间排序
        List<GAScheduleResult> machineTasks = existingTasks.stream()
                .filter(t -> t.getMachineId() == machine.getId())
                .sorted(Comparator.comparing(GAScheduleResult::getStartTime))
                .collect(Collectors.toList());

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

        // 获取当前/上一个班次
        TimeSegment slot = getCurrentOrPrevShift(machine, currentTime);

        if (slot == null) {
            return null;
        }
       int processingTime1=(int)Math.ceil( processingTime/slot.getEfficiency());
        // 计算候选开始/结束时间（当前时间往前推加工时长）
        LocalDateTime startCandidate = currentTime.minusSeconds(processingTime1);
        LocalDateTime endCandidate = currentTime;

        // 检查是否在可用时间段内
        if (startCandidate.isBefore(slot.getStart())) {
            // 放不下，寻找后续可用时间
            return checkMachineShift(machine, processingTime, currentTime, startTime, machineTasks);
        } else {
            // 生成可用时间段
            ScheduleResultDetail time = new ScheduleResultDetail();
            time.setKey(slot.getKey());
            // 计算相对基准时间的分钟数（对应原代码TotalMinutes
            time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, startCandidate));
            time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, endCandidate));
            times.add(time);
            return times;
        }
    }

    /**
     * 获取设备当前或上一个有效班次
     * @param machine 目标设备
     * @param time 目标时间
     * @return 有效班次，无则递归生成后返回
     */
    private TimeSegment getCurrentOrPrevShift(Machine machine, LocalDateTime time) {
        TimeSegment start = null;

        // 找到最后一个可用班次：未使用、非维护类型、开始时间早于目标时间
        // 倒序遍历找最后一个符合条件的班次
        List<TimeSegment> availability = machine.getAvailability();
        for (int i = availability.size() - 1; i >= 0; i--) {
            TimeSegment slot = availability.get(i);
            if (!slot.isUsed()
                    && slot.getType() != SegmentType.MAINTENANCE
                    && slot.getStart().isBefore(time)) {
                start = slot;
                break;
            }
        }

        // 若未找到班次，且目标时间晚于所有班次的结束时间 → 生成新班次并递归
        if (start == null) {
            // 获取所有班次的最大结束时间
            Optional<LocalDateTime> maxEndTime = availability.stream()
                    .map(TimeSegment::getEnd)
                    .max(LocalDateTime::compareTo);

            // 检查是否目标时间晚于最大结束时间（处理空列表情况）
            boolean isTimeAfterMaxEnd = maxEndTime.map(end -> time.isAfter(end)).orElse(true);
            if (isTimeAfterMaxEnd) {
                // 生成新的时间段并添加到设备可用班次中
                LocalDateTime generateStartTime = maxEndTime.orElse(LocalDateTime.now());
                List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, generateStartTime,0);
                machine.getAvailability().addAll(timeSegments);

                // 更新机器列表中的对应机器
                Machine m = machines.stream()
                        .filter(t -> t.getId() == machine.getId())
                        .findFirst()
                        .orElse(null);
                if (m != null) {
                    MachineTimeline machineTimeline = machineScheduler.getOrCreateTimeline(m);
                    // 原代码注释：m.Availability = machineTimeline.Segments;
                    // 如需启用请补充：m.setAvailability(machineTimeline.getSegments());
                }

                // 递归调用，重新获取有效班次
                return getCurrentOrPrevShift(machine, time);
            }
        }

        return start;
    }
    /**
     * 检查设备班次，计算满足加工时长的可用时间段
     * @param machine 目标设备
     * @param processingTime 总加工时长（分钟）
     * @param currentTime 当前时间
     * @param startTime 开始时间阈值
     * @param machineTasks 设备已有任务列表
     * @return 分段的可用时间段列表，无可用时间返回null
     */
    private List<ScheduleResultDetail> checkMachineShift(Machine machine, int processingTime,
                                               LocalDateTime currentTime, LocalDateTime startTime,
                                               List<GAScheduleResult> machineTasks) {
        int remainingTime = processingTime;

        // 初始化上一班次结束时间（对应原2000-01-01的初始值）
        LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0);
        List<ScheduleResultDetail> times = new ArrayList<>();

        while (remainingTime > 0) {
            // 开始时间阈值超过当前时间，无可用时间
            if (startTime.isAfter(currentTime)) {
                return null;
            }

            // 获取当前/上一个有效班次
            TimeSegment shift = getCurrentOrPrevShift(machine, currentTime);
            if (shift == null) {
                return null;
            }
            LocalDateTime shiftStart = shift.getStart();
            LocalDateTime shiftEnd = shift.getEnd();

            // 非初始状态（上一班次已存在），检查班次连续性
            if (prevEnd.getYear()!=2000) {
                // 检查上一班次和当前班次之间是否有任务
                if (prevEnd.isAfter(shiftEnd)) {
                    // 查找任务：任务开始时间在当前班次开始 ~ 上一班次结束之间
                    LocalDateTime finalPrevEnd = prevEnd;
                    Optional<GAScheduleResult> task = machineTasks.stream()
                            .filter(t -> baseTime.plusSeconds(t.getStartTime()).isAfter(shiftStart)
                                    && baseTime.plusSeconds(t.getStartTime()).isBefore(finalPrevEnd))
                            .findFirst();
                    boolean  hasTask=  CheckTask( machine, machineTasks, prevEnd, shiftStart);
                    if (hasTask) {
                        // 班次间有任务，重置状态重新查找
                        currentTime = shiftStart;
                        remainingTime = processingTime;
                        prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0);
                        times.clear();
                        continue;
                    }
                }

            }

            // 调整班次有效结束时间（不超过当前时间）
            LocalDateTime effectiveEnd = shiftEnd.isAfter(currentTime) ? currentTime : shiftEnd;

            // 计算班次可用时长
            Duration availableDuration = Duration.between(shiftStart, effectiveEnd);
            long availableMinutes = availableDuration.getSeconds();


            // 当前班次可处理的时长（不超过剩余需要的时长）
            int processableMinutes = (int) Math.min(remainingTime, availableMinutes);

            long availableSeconds_e =Math.round(processableMinutes/shift.getEfficiency()) ;

            // 计算当前班次的有效开始时间
            LocalDateTime effectiveStart = effectiveEnd.minusSeconds(availableSeconds_e);
            prevEnd = effectiveStart; // 更新上一班次结束时间
            remainingTime -= processableMinutes; // 剩余时长递减
            currentTime = effectiveStart; // 更新当前时间，继续循环

            // 生成当前班次的时间片段
            ScheduleResultDetail time = new ScheduleResultDetail();
            time.setKey(shift.getKey());


            time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
            time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveEnd));

            times.add(time);
        }

        return times;
    }
    private  CopyOnWriteArrayList<TimeSegment> RemoveMachineAvailable(Machine machine, ScheduleResultDetail geneDetails,TimeSegment targetSegment) {
      return   RemoveMachineAvailable( machine,  geneDetails, targetSegment, true);

    }
    // 把目标 availability 按本次排程切成“剩余可用段”和“本次已占用段”，并把占用段 key 回写到 geneDetails。
    private  CopyOnWriteArrayList<TimeSegment> RemoveMachineAvailable(Machine machine, ScheduleResultDetail geneDetails,TimeSegment targetSegment,boolean islockMachineTime) {


        LocalDateTime geneStartTime = baseTime.plusSeconds(geneDetails.getStartTime());

        LocalDateTime geneEndTime = baseTime.plusSeconds(geneDetails.getEndTime());

        CopyOnWriteArrayList<TimeSegment> usedSegments=new CopyOnWriteArrayList<>();
        if (targetSegment.getStart().isBefore(geneStartTime)&&targetSegment.getEnd().isAfter(geneEndTime)) {
            TimeSegment usedSegment=new TimeSegment();
            usedSegment.setStart(targetSegment.getStart());
            usedSegment.setEnd(geneStartTime);
            usedSegment.setHoliday(false);
            usedSegment.setKey(UUID.randomUUID().toString());
            usedSegment.setType(SegmentType.REGULAR);
            usedSegment.setUsed(false);
            usedSegment.setKey(UUID.randomUUID().toString());
            usedSegments.add(usedSegment);

            TimeSegment usedSegment2=new TimeSegment();
            usedSegment2.setStart(geneStartTime.plusSeconds(1));
            usedSegment2.setEnd(geneEndTime);
            usedSegment2.setHoliday(false);
            usedSegment2.setKey(UUID.randomUUID().toString());
            usedSegment2.setType(SegmentType.REGULAR);
            if(islockMachineTime)
            {
                usedSegment2.setUsed(true);
            }else {
                usedSegment2.setUsed(false);
            }

            usedSegments.add(usedSegment2);

            geneDetails.setKey(usedSegment2.getKey());
            targetSegment.setStart(geneEndTime);

        }
         else if (targetSegment.getEnd().isAfter(geneEndTime)) {
                TimeSegment usedSegment=new TimeSegment();
                usedSegment.setStart(baseTime.plusSeconds(geneDetails.getStartTime()));
                usedSegment.setEnd(geneEndTime);
                usedSegment.setHoliday(false);
                usedSegment.setKey(UUID.randomUUID().toString());
                usedSegment.setType(SegmentType.REGULAR);
            if(islockMachineTime)
            {
                usedSegment.setUsed(true);
            }else {
                usedSegment.setUsed(false);
            }
                usedSegments.add(usedSegment);
                geneDetails.setKey(usedSegment.getKey());
                targetSegment.setStart(geneEndTime.plusSeconds(1));
            }else if (targetSegment.getStart().isBefore(geneStartTime)) {
             //换型时可能需要把前面的时间分割处理
                TimeSegment usedSegment=new TimeSegment();
                usedSegment.setStart(targetSegment.getStart());
                usedSegment.setEnd(geneStartTime);
                usedSegment.setHoliday(false);
                usedSegment.setKey(UUID.randomUUID().toString());
                usedSegment.setType(SegmentType.REGULAR);
                usedSegment.setUsed(false);
                usedSegment.setKey(UUID.randomUUID().toString());
                usedSegments.add(usedSegment);
                geneDetails.setKey(targetSegment.getKey());
                targetSegment.setStart(geneStartTime.plusSeconds(1));
            if(islockMachineTime)
            {
                targetSegment.setUsed(true);
            }else {
                targetSegment.setUsed(false);
            }
            }else {
            if(islockMachineTime)
            {
                targetSegment.setUsed(true);
            }else {
                targetSegment.setUsed(false);
            }
            }

return  usedSegments;
//            if(usedSegments!=null&&usedSegments.size()>0)
//            {
//                    machine.getAvailability().addAll(usedSegments);
//                    machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
//            }
    }

    private void RemoveMachineAvailable1(Machine machine, ScheduleResultDetail geneDetails,TimeSegment targetSegment1) {
        List<TimeSegment> timeSegments = new ArrayList<>();

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

        if (index > -1) {
            TimeSegment targetSegment = availabilitySnapshot.get(index);
            LocalDateTime geneEndTime = baseTime.plusSeconds(geneDetails.getEndTime());

            if (targetSegment.getEnd().isAfter(geneEndTime)) {
                TimeSegment usedSegment = new TimeSegment();
                usedSegment.setStart(baseTime.plusSeconds(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()) {
            availabilitySnapshot.addAll(timeSegments);
        }
        availabilitySnapshot.sort(Comparator.comparing(TimeSegment::getStart));
        // 关键修复2：加锁（若多线程访问），避免并发修改

            machine.setAvailability(availabilitySnapshot);

    }

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

      List<String> keys=  geneDetails.stream().
                filter(t->t.getUsedSegment()==null||t.getUsedSegment().size()==0)
                .map(ScheduleResultDetail::getKey)
                .collect(Collectors.toList());

        List<String> keys1= geneDetails.stream().
                filter(t->t.getUsedSegment()!=null)
                .flatMap(detail -> detail.getUsedSegment().stream())
                .map(TimeSegment::getKey).collect(Collectors.toList());
if(keys1!=null&&keys1.size()>0) {
    keys.addAll(keys1);
}

        List<TimeSegment> toUpdate = machine.getAvailability().stream()
                .filter(t -> keys.contains(t.getKey()))
                .collect(Collectors.toList());

// 然后批量修改
        toUpdate.forEach(t -> t.setUsed(false));



    }

    public void AddMachineAvailable1(Machine machine, List<ScheduleResultDetail> geneDetails) {
        if (geneDetails == null || geneDetails.isEmpty()) return;
        CopyOnWriteArrayList<TimeSegment> availabilitySnapshot = new CopyOnWriteArrayList<>(machine.getAvailability());

        for (ScheduleResultDetail detail : geneDetails) {
            if(detail.getUsedSegment()!=null&&detail.getUsedSegment().size()>0)
            {
                List<TimeSegment> availabilitySnapshot1=  detail.getUsedSegment();
                availabilitySnapshot1.forEach(t->t.setUsed(false));
            }else {
                availabilitySnapshot.stream()
                        .filter(t -> t.getKey().equals(detail.getKey()))
                        .findFirst()
                        .ifPresent(t -> t.setUsed(false));
            }

        }
        availabilitySnapshot= MergeSegments(availabilitySnapshot,false);
        synchronized (machine.getAvailability()) {
            machine.setAvailability(availabilitySnapshot);
        }
    }
    /**
     * 分割设备可用时间段
     * @param machine 设备实例
     * @param timeSegment 待分割的时间片段
     * @param start 分割起始时间
     */
    private void spiltMachineAvailable(Machine machine, TimeSegment timeSegment, LocalDateTime start,boolean isJit) {
        List<TimeSegment> timeSegments = new ArrayList<>();

        // 查找待分割片段在设备可用列表中的索引，对应C#的 FindIndex
        int inx = machine.getAvailability().stream()
                .filter(t -> t.getKey().equals(timeSegment.getKey()))
                .findFirst()
                .map(machine.getAvailability()::indexOf)
                .orElse(-1);
        if (inx > -1) {


            // 创建分割后的前半段时间片段
            TimeSegment time = new TimeSegment();
            if(isJit)
            {
                time.setStart(start.plusSeconds(1));
                // 对应C#的 start.AddSeconds(-1)
                time.setEnd(timeSegment.getEnd());
            }else {
                time.setStart(timeSegment.getStart());
                // 对应C#的 start.AddSeconds(-1)
                time.setEnd(start.plusSeconds(-1));
            }
            time.setHoliday(false); //  IsHoliday = false
            // 对应C#的 Guid.NewGuid().ToString()，生成唯一标识
            time.setKey(UUID.randomUUID().toString());
            time.setType(SegmentType.REGULAR);
            time.setUsed(false); // IsUsed = false


            timeSegments.add(time);

            // 更新原片段的起始时间为分割时间，对应C#的 machine.Availability[inx].Start = start
            machine.getAvailability().get(inx).setStart(start);
        }

        // 批量添加分割后的片段（空判断优化，符合Java规范）
        if (timeSegments != null && !timeSegments.isEmpty()) {
            machine.getAvailability().addAll(timeSegments);
        }

        // 按起始时间排序
        machine.getAvailability().sort((a, b) -> a.getStart().compareTo(b.getStart()));
    }

    private CopyOnWriteArrayList<TimeSegment> MergeSegments(CopyOnWriteArrayList<TimeSegment> segments,boolean isJit) {
        CopyOnWriteArrayList<TimeSegment> maintenanceSegments = segments.stream()
                .filter(t -> t.getType() == SegmentType.MAINTENANCE)
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));

        CopyOnWriteArrayList<TimeSegment> unusedRegularSegments = segments.stream()
                .filter(t -> t.getType() != SegmentType.MAINTENANCE && !t.isUsed())
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));

        CopyOnWriteArrayList<TimeSegment> usedRegularSegments = segments.stream()
                .filter(t -> t.getType() != SegmentType.MAINTENANCE && t.isUsed())
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));

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

        CopyOnWriteArrayList<TimeSegment> result = new CopyOnWriteArrayList<>(mergedUnused);
        result.addAll(usedRegularSegments);
        result.addAll(maintenanceSegments);
        if(isJit)
        {
            result.sort(Comparator.comparing(TimeSegment::getEnd).reversed());
        }else {
            result.sort(Comparator.comparing(TimeSegment::getStart));
        }
        return result;
    }


}
