package com.aps.service.plan;




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

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

public class MachineSchedulerService {

    // 全局缓存（线程安全）
    private static final ConcurrentHashMap<Long, MachineTimeline> timelineCache = new ConcurrentHashMap<>();
    private final ReentrantLock cacheLock = new ReentrantLock();
    private LocalDateTime currentTime;
    private List<Holiday> holidays;

    public MachineSchedulerService( LocalDateTime currentTime) {
        this.holidays = holidays != null ? holidays : new ArrayList<>();
        this.currentTime = currentTime;
    }
    public MachineSchedulerService(List<Holiday> holidays, LocalDateTime currentTime) {
        this.holidays = holidays != null ? holidays : new ArrayList<>();
        this.currentTime = currentTime;
    }
    public void ClearMachineCache(long machineId) {
        timelineCache.remove(machineId);
    }
    public MachineTimeline getOrCreateTimeline(Machine machine,boolean isCache) {
        long machineId = machine.getId();

        // 尝试从缓存获取
        MachineTimeline timeline = timelineCache.get(machineId);
        if (timeline != null&&isCache) {
            // 检查有效期（4小时刷新）
            if (Duration.between(timeline.getLastUpdated(), LocalDateTime.now()).toMinutes() < 10) {
                return timeline;
            }
        }

        // 创建新时间线（60天范围）
        MachineTimeline newTimeline = generateTimeline(machine);
      //  newTimeline.setSegments(mergeSegments(newTimeline.getSegments()));

         timelineCache.put(machineId, newTimeline);
        return newTimeline;
    }
    public MachineTimeline getOrCreateTimeline(Machine machine) {
        return  getOrCreateTimeline(machine,true);


    }

    public LocalDateTime GetEndTime(Long machineId) {
        MachineTimeline timeline = timelineCache.get(machineId);
        if(timeline!=null)
        {
            return timeline.getValidTo();
        }
        return null;
    }

    private MachineTimeline generateTimeline(Machine machine) {
        MachineTimeline timeline = new MachineTimeline();
        timeline.setMachineId(machine.getId());
        timeline.setValidFrom(currentTime);
        timeline.setValidTo(currentTime.plusDays(200));
        timeline.setLastUpdated(LocalDateTime.now());

        LocalDate currentDate = currentTime.toLocalDate();
        LocalDate endDate = currentTime.plusDays(200).toLocalDate();

        CopyOnWriteArrayList<TimeSegment> allSegments = new CopyOnWriteArrayList<>();

        while (!currentDate.isAfter(endDate)) {
            // 检查是否在假期内
            boolean isHolidayPeriod = isHoliday(machine,currentDate);

            // 生成当日时间段
            CopyOnWriteArrayList<TimeSegment> daySegments = calculateDaySegments(machine, currentDate, isHolidayPeriod);
            allSegments.addAll(daySegments);

            // 跳到下一天
            currentDate = currentDate.plusDays(1);
        }

        // 合并连续时间段
        timeline.setSegments(mergeSegments(allSegments));

        // 处理维护窗口
        if (machine.getMaintenanceWindows() != null&&machine.getMaintenanceWindows().size()>0 && !timeline.getSegments().isEmpty()) {
            LocalDateTime maxEnd = timeline.getSegments().stream()
                    .map(TimeSegment::getEnd)
                    .max(LocalDateTime::compareTo)
                    .orElse(LocalDateTime.MIN);


            List<MaintenanceWindow> MaintenanceWindow=  mergeMaintenanceWindows(machine.getMaintenanceWindows());


            for (MaintenanceWindow maintenanceWindow : MaintenanceWindow) {
                if (maintenanceWindow.getStartTime().isAfter(maxEnd) ||
                        maintenanceWindow.getEndTime().isBefore(currentTime)) {
                    continue;
                }
                if(maintenanceWindow.getStartTime().isBefore(currentTime)&&maintenanceWindow.getEndTime().isAfter(maxEnd))
                {
                    timeline.setSegments(new CopyOnWriteArrayList<>());
                    currentTime=maintenanceWindow.getEndTime();
                    timeline= generateTimeline(machine);
                    break;
                }else {
                    updateSegmentsForMaintenance(timeline.getSegments(),
                            maintenanceWindow.getStartTime(), maintenanceWindow.getEndTime());
                }
            }
        }

        return timeline;
    }

    public CopyOnWriteArrayList<TimeSegment> generateTimeSegment(Machine machine, LocalDateTime currentTime,int days) {
       if(days==0)
       {
           days=200;
       }


        cacheLock.lock();

        Long machineId = machine.getId();
        MachineTimeline timeline = timelineCache.get(machineId);
try {

    if (timeline == null) {
        if(currentTime==null)
        {
            currentTime=LocalDateTime.now();
        }
        timeline = new MachineTimeline();
        timeline.setMachineId(machine.getId());
        timeline.setValidFrom(currentTime);
        timeline.setValidTo(currentTime.plusDays(days));
        timeline.setLastUpdated(LocalDateTime.now());
        timeline.setSegments(new CopyOnWriteArrayList<>());
    } else {
        if(currentTime==null)
        {
            currentTime=timeline.getValidTo().plusDays(1);
        }
        if (timeline.getValidTo().compareTo(currentTime) > 0) {
            LocalDateTime currentTime1=currentTime;
            CopyOnWriteArrayList<TimeSegment> timeSegments= timeline.getSegments().stream()
                    .filter(t->t.getStart().isAfter(currentTime1)||t.getStart().isBefore(currentTime1))
                    .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
            return ProductionDeepCopyUtil.deepCopyList(timeSegments,TimeSegment.class);

        } else {
            timeline.setValidTo(currentTime.plusDays(days));
            timeline.setLastUpdated(LocalDateTime.now());
        }
    }
}finally {
    cacheLock.unlock();
}

        LocalDate currentDate = currentTime.toLocalDate();
        LocalDate endDate = currentTime.plusDays(days).toLocalDate();

        CopyOnWriteArrayList<TimeSegment> segments = new CopyOnWriteArrayList<>();

        while (!currentDate.isAfter(endDate)) {
            // 检查是否在假期内
            boolean isHolidayPeriod = isHoliday(machine,currentDate);

            // 生成当日时间段
            List<TimeSegment> daySegments = calculateDaySegments(machine, currentDate, isHolidayPeriod);
            segments.addAll(daySegments);

            // 跳到下一天
            currentDate = currentDate.plusDays(1);
        }

        // 处理维护窗口
        if (machine.getMaintenanceWindows() != null&&machine.getMaintenanceWindows().size()>0 && !segments.isEmpty()) {
            LocalDateTime maxEnd = segments.stream()
                    .map(TimeSegment::getEnd)
                    .max(LocalDateTime::compareTo)
                    .orElse(LocalDateTime.MIN);

          List<MaintenanceWindow> MaintenanceWindow=  mergeMaintenanceWindows(machine.getMaintenanceWindows());
            for (MaintenanceWindow maintenanceWindow : MaintenanceWindow) {
                if (maintenanceWindow.getStartTime().isAfter(maxEnd) ||
                        maintenanceWindow.getEndTime().isBefore(currentTime)) {
                    continue;
                }
                if(maintenanceWindow.getStartTime().isBefore(currentTime)&&maintenanceWindow.getEndTime().isAfter(maxEnd))
                {
                    currentTime=maintenanceWindow.getEndTime();
                    segments= generateTimeSegment(machine,currentTime,days);
                    break;
                }else {
                    updateSegmentsForMaintenance(segments, maintenanceWindow.getStartTime(), maintenanceWindow.getEndTime());
                }
            }
        }

        // 添加新生成的段到时间线
        timeline.getSegments().addAll(copyTimeSegments(segments));

        // 合并连续时间段
        timeline.setSegments(mergeSegments(timeline.getSegments()));
        segments = mergeSegments(segments);


    cacheLock.lock();
    try {
        timelineCache.put(machineId, timeline);
    }finally {
        cacheLock.unlock();
    }
    return segments;




    }

    /**
     * 追加片段并去重、排序（避免冗余片段和遍历混乱）
     */
    public void addSegmentsWithDeduplication(Machine machine, List<TimeSegment> newSegments) {
        // 空判断：新片段为null或空集合时直接返回，对应C#的 newSegments == null || newSegments.Count == 0
        if (newSegments == null || newSegments.isEmpty()) {
            return;
        }

        // 追加新片段，对应C#的 machine.Availability.AddRange(newSegments)
        machine.getAvailability().addAll(newSegments);

        // 合并片段（去重+排序），并重新赋值给设备的可用片段列表，对应C#的 machine.Availability = MergeSegments(...)
        CopyOnWriteArrayList<TimeSegment> mergedSegments = mergeSegments(machine.getAvailability());
        machine.setAvailability(mergedSegments);
    }

    private boolean isHoliday(Machine machine,LocalDate currentDate) {
        if(machine.getHolidays()==null||machine.getHolidays().size()==0)
            return  false;
        for (Holiday holiday : machine.getHolidays()) {
            LocalDateTime holidayStart = holiday.getStart();
            LocalDateTime holidayEnd = holiday.getEnd();

            if (holidayStart != null && holidayEnd != null) {
                LocalDate holidayStartDate = holidayStart.toLocalDate();
                LocalDate holidayEndDate = holidayEnd.toLocalDate();

                if ((currentDate.isEqual(holidayStartDate) || currentDate.isAfter(holidayStartDate)) &&
                        (currentDate.isEqual(holidayEndDate) || currentDate.isBefore(holidayEndDate))) {
                    return true;
                }
            }
        }
        return false;
    }

    private CopyOnWriteArrayList<TimeSegment> calculateDaySegments(Machine machine, LocalDate date, boolean isHoliday) {
        CopyOnWriteArrayList<TimeSegment> segments = new CopyOnWriteArrayList<>();

        if (isHoliday) {
            // 假期：只处理特定日期的班次
            List<Shift> shifts = machine.getShifts().stream()
                    .filter(s -> s.getDays() == null &&
                                    date.compareTo(s.getStartDate().toLocalDate())>=0
                                    &&s.getEndDate().toLocalDate().compareTo(date)>=0
                            )
                    .collect(Collectors.toList());

            for (Shift shift : shifts) {
                LocalDateTime shiftStart = date.atTime(shift.getStartTime());
                LocalDateTime shiftEnd = shift.getEndTime().isBefore(shift.getStartTime()) ?
                        date.plusDays(1).atTime(shift.getEndTime()) :
                        date.atTime(shift.getEndTime());
                TimeSegment timeSegment=  new TimeSegment(
                        shiftStart,
                        shiftEnd,
                        shift.isTemporaryShift() ? SegmentType.TEMP : SegmentType.REGULAR,
                        false
                );
                timeSegment.setEfficiency(shift.getEfficiency());
                segments.add(timeSegment);
            }
        } else {
            // 非假期：处理常规班次
            List<Shift> shifts = machine.getShifts().stream()
                    .filter(s ->
                            date.compareTo(s.getStartDate().toLocalDate())>=0
                            &&s.getEndDate().toLocalDate().compareTo(date)>=0
                            && s.getDays() != null
                            && containsDay(s.getDays(), date.getDayOfWeek()))
                    .collect(Collectors.toList());
if(shifts==null||shifts.size()==0) {


  long days=Math.abs(ChronoUnit.DAYS.between(LocalDate.now(),date));
    if(days>600)
    {
        segments.add(new TimeSegment
                        (
           date.atTime(0,0,0),
                                date.atTime(23,59,59),
                      SegmentType.REGULAR,
                     false
                        ));
        return segments;
    }else {

        LocalDate sd = LocalDate.of(2000, 1, 1);
        shifts = machine.getShifts().stream()
                .filter(s -> sd.compareTo(s.getStartDate().toLocalDate()) == 0 && s.getDays() != null
                        && containsDay(s.getDays(), date.getDayOfWeek()))
                .collect(Collectors.toList());
    }

}
            for (Shift shift : shifts) {
                LocalDateTime shiftStart = date.atTime(shift.getStartTime());
                LocalDateTime shiftEnd = shift.getEndTime().isBefore(shift.getStartTime()) ?
                        date.plusDays(1).atTime(shift.getEndTime()) :
                        date.atTime(shift.getEndTime());
                TimeSegment timeSegment=  new TimeSegment(
                        shiftStart,
                        shiftEnd,
                        shift.isTemporaryShift() ? SegmentType.TEMP : SegmentType.REGULAR,
                        false
                );
                timeSegment.setEfficiency(shift.getEfficiency());
                segments.add(timeSegment);
            }
        }

        return segments;
    }

    /**
     * 检查班次是否包含指定的星期几
     * JSON中的Day映射：0=周日, 1=周一, 2=周二, ..., 6=周六
     * Java DayOfWeek: MONDAY=1, TUESDAY=2, ..., SUNDAY=7
     */
    private boolean containsDay(Set<Integer> shiftDays, DayOfWeek targetDay) {
        if (shiftDays == null || shiftDays.isEmpty()) {
            return false;
        }

        // 将Java的DayOfWeek转换为JSON格式的数字
        int targetDayValue = targetDay.getValue();

        // 特殊处理周日：JSON中0表示周日，Java中Sunday是7
        if (targetDay == DayOfWeek.SUNDAY) {
            return shiftDays.contains(0) || shiftDays.contains(7);
        }

        return shiftDays.contains(targetDayValue);
    }

    private CopyOnWriteArrayList<TimeSegment> mergeSegments(CopyOnWriteArrayList<TimeSegment> segments1) {

        CopyOnWriteArrayList<TimeSegment> segments= ProductionDeepCopyUtil.deepCopyList(segments1,TimeSegment.class);
        if(segments==null||segments.size()==0)
        {
            return null;
        }

        CopyOnWriteArrayList<TimeSegment> maintenanceSegments1 = segments.stream()
                .filter(t ->t.getType()==null)
                .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        if(maintenanceSegments1.size()>0)
        {
            int i=0;
        }

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

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

        // 按开始时间排序
        otherSegments.sort(Comparator.comparing(TimeSegment::getStart));

        Stack<TimeSegment> merged = new Stack<>();

        for (TimeSegment seg : otherSegments) {
            if (!merged.isEmpty() && !merged.peek().getEnd().isBefore(seg.getStart())) {
                TimeSegment top = merged.peek();
                if (top.getEnd().isBefore(seg.getEnd())) {
                    top.setEnd(seg.getEnd());
                }
            } else {
                seg.setKey(UUID.randomUUID().toString());
                merged.push(seg);
            }
        }

        CopyOnWriteArrayList<TimeSegment> result = new CopyOnWriteArrayList<>(merged);
        result.addAll(maintenanceSegments);

        // 按开始时间排序
        result.sort(Comparator.comparing(TimeSegment::getStart));
        return result;
    }


    private List<MaintenanceWindow> mergeMaintenanceWindows(List<MaintenanceWindow> segments1) {

        List<MaintenanceWindow> segments= ProductionDeepCopyUtil.deepCopyList(segments1,MaintenanceWindow.class);
        if(segments==null||segments.size()==0)
        {
            return null;
        }

        // 按开始时间排序
        segments.sort(Comparator.comparing(MaintenanceWindow::getStartTime));

        Stack<MaintenanceWindow> merged = new Stack<>();

        for (MaintenanceWindow seg : segments) {
            if (!merged.isEmpty() && !merged.peek().getEndTime().isBefore(seg.getStartTime())) {
                MaintenanceWindow top = merged.peek();
                if (top.getEndTime().isBefore(seg.getEndTime())) {
                    top.setEndTime(seg.getEndTime());
                }
            } else {

                merged.push(seg);
            }
        }

        List<MaintenanceWindow> result = new CopyOnWriteArrayList<>(merged);

        // 按开始时间排序
        result.sort(Comparator.comparing(MaintenanceWindow::getStartTime));
        return result;
    }

    private void updateSegmentsForMaintenance(List<TimeSegment> segments, LocalDateTime maintenanceStart, LocalDateTime maintenanceEnd) {
        if (segments.isEmpty()) return;

        // 1. 二分查找
        int firstIndex = binarySearchSegment(segments, maintenanceStart);
        if (firstIndex == segments.size()) return;

        // 2. 收集有交集的段
        List<Integer> indicesToProcess = new ArrayList<>();
        int i = firstIndex;
        while (i < segments.size() && segments.get(i).getStart().isBefore(maintenanceEnd)) {
            if (segments.get(i).getEnd().isAfter(maintenanceStart)) {
                indicesToProcess.add(i);
            }
            i++;
        }

        // 3. 倒序处理
        for (int j = indicesToProcess.size() - 1; j >= 0; j--) {
            int index = indicesToProcess.get(j);
            TimeSegment seg = segments.get(index);
            LocalDateTime segStart = seg.getStart();
            LocalDateTime segEnd = seg.getEnd();

            // 完全覆盖
            if ((maintenanceStart.isBefore(segStart) || maintenanceStart.equals(segStart)) &&
                    (maintenanceEnd.isAfter(segEnd) || maintenanceEnd.equals(segEnd))) {
                segments.remove(index);
            }
            // 维护时间段在段内部
            else if (maintenanceStart.isAfter(segStart) && maintenanceEnd.isBefore(segEnd)) {
                // 分割：原段变成前半段 [segStart, maintenanceStart)
                seg.setEnd(maintenanceStart);

                // 添加后半段 [maintenanceEnd, segEnd)
                segments.add(index + 1, new TimeSegment(
                        maintenanceEnd,
                        segEnd,
                        seg.getType(),
                        seg.isHoliday()
                ));
            }
            // 维护时间段覆盖开始部分
            else if (maintenanceStart.isBefore(segStart) || maintenanceStart.equals(segStart)) {
                // 保留：维护时间段之后的部分 [maintenanceEnd, segEnd)
                seg.setStart(maintenanceEnd);
            }
            // 维护时间段覆盖结束部分
            else if (maintenanceEnd.isAfter(segEnd) || maintenanceEnd.equals(segEnd)) {
                // 保留：维护时间段之前的部分 [segStart, maintenanceStart)
                seg.setEnd(maintenanceStart);
            }
        }

//        segments.add(new TimeSegment(
//                maintenanceStart,
//                maintenanceEnd,
//                SegmentType.MAINTENANCE,
//                false
//        ));
    }

    private int binarySearchSegment(List<TimeSegment> segments, LocalDateTime maintenanceStart) {
        int left = 0;
        int right = segments.size() - 1;
        int result = segments.size();

        while (left <= right) {
            int mid = left + (right - left) / 2;
            TimeSegment seg = segments.get(mid);

            if ((seg.getStart().isBefore(maintenanceStart) || seg.getStart().equals(maintenanceStart)) &&
                    maintenanceStart.isBefore(seg.getEnd())) {
                return mid;
            }

            if (seg.getEnd().isBefore(maintenanceStart) || seg.getEnd().equals(maintenanceStart)) {
                left = mid + 1;
            } else {
                result = mid;
                right = mid - 1;
            }
        }

        return result;
    }

    private List<TimeSegment> copyTimeSegments(List<TimeSegment> originals) {
        return originals.stream()
                .map(seg -> {
                    TimeSegment copy = new TimeSegment();
                    copy.setStart(seg.getStart());
                    copy.setEnd(seg.getEnd());
                    copy.setType(seg.getType());
                    copy.setHoliday(seg.isHoliday());
                    copy.setUsed(seg.isUsed());
                    copy.setKey(seg.getKey());
                    return copy;
                })
                .collect(Collectors.toList());
    }

    // 清理缓存的方法
    public static void clearCache() {
        timelineCache.clear();
    }

    public static int getCacheSize() {
        return timelineCache.size();
    }
}