package com.ylx.common.utils;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 预约时段生成工具类
 * 规则说明：
 * 1. 未来日期：生成全天所有完整不跨天时段起点，步进 = 服务时长
 * 2. 当天日期：只返回【当前时间之后】的时段，已过期时段全部过滤
 * 示例：时长30分钟，当前10:01 → 第一个时段10:30；当前10:35 → 第一个时段11:00
 */
public class TimeSlotUtil {

    /** 一天总分钟数 24*60 */
    private static final int MINUTES_PER_DAY = 24 * 60;
    /** 一天总纳秒数 */
    private static final long DAY_NANOS = (long) MINUTES_PER_DAY * 60_000_000_000L;

    /**
     * 获取指定日期可预约时段起点列表
     * @param queryDate 查询目标日期
     * @param durationMin 单次服务时长（分钟，同时作为时段步进，必须>0且<=1440）
     * @return 可用时段 LocalTime 集合
     */
    public static List<LocalTime> getAvailableTimeSlots(LocalDate queryDate, int durationMin) {
        // 参数合法性拦截
        if (durationMin <= 0 || durationMin > MINUTES_PER_DAY || queryDate == null) {
            return Collections.emptyList();
        }

        LocalDate today = LocalDate.now();
        // 非今天：返回全天完整时段
        if (!queryDate.isEqual(today)) {
            return generateFullDaySlots(durationMin);
        }

        // 今日逻辑：先生成全天 bounded 时段，再过滤当前时间之前的
        LocalTime now = LocalTime.now();
        LocalTime firstValidSlot = getNextStrictSlot(now, durationMin);
        LocalTime latestStart = LocalTime.of(23, 59);
        if (firstValidSlot.isAfter(latestStart)) {
            return Collections.emptyList();
        }

        List<LocalTime> slotList = new ArrayList<>();
        for (LocalTime slot : generateFullDaySlots(durationMin)) {
            if (slot.isBefore(firstValidSlot)) {
                continue;
            }
            if (slot.isAfter(latestStart)) {
                break;
            }
            slotList.add(slot);
        }
        return slotList;
    }

    /**
     * 生成全天完整时段起点（00:00开始，按服务时长步进）
     * @param durationMin 步进/服务时长
     * @return 全天所有时段起点
     */
    private static List<LocalTime> generateFullDaySlots(int durationMin) {
        int totalSlotCount = MINUTES_PER_DAY / durationMin;
        List<LocalTime> slotList = new ArrayList<>(totalSlotCount);
        LocalTime current = LocalTime.MIDNIGHT;
        for (int i = 0; i < totalSlotCount; i++) {
            slotList.add(current);
            current = current.plusMinutes(durationMin);
        }
        return slotList;
    }

    /**
     * 获取严格大于传入时间的下一个时段起点
     * 步进等于服务时长，自动向上取档
     * 示例：
     * durationMin=30
     *  10:00:00 → 10:30
     *  10:01:00 → 10:30
     *  10:30:00 → 11:00
     * @param time 基准时间
     * @param durationMin 时段步进分钟
     * @return 下一档时段起点，超出当日则返回00:00
     */
    public static LocalTime getNextStrictSlot(LocalTime time, int durationMin) {
        // 单步对应的纳秒值
        long stepNanos = (long) durationMin * 60_000_000_000L;
        // 当前时间纳秒 + 1纳秒，刚好等于时段边界也会进到下一档
        long currentNano = time.toNanoOfDay() + 1;

        // 向上取整计算下一个时段纳秒点
        long nextSlotNano = ((currentNano / stepNanos) + 1) * stepNanos;

        // 超过当天时间范围，返回次日零点（上层会用latestStart过滤掉）
        if (nextSlotNano >= DAY_NANOS) {
            return LocalTime.MIDNIGHT;
        }
        return LocalTime.ofNanoOfDay(nextSlotNano);
    }

}