package com.njcn.gather.tool.adddata.component;

import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

/**
 * 时间槽计算组件。
 */
@Component
public class AddDataTimeSlotCalculator {

    /**
     * 构建自然时间槽列表。
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param intervalMinutes 步长，单位分钟
     * @return 时间槽列表
     */
    public List<LocalDateTime> buildTimeSlots(LocalDateTime startTime, LocalDateTime endTime, int intervalMinutes) {
        if (intervalMinutes <= 0) {
            throw new IllegalArgumentException("时间步长必须大于 0");
        }
        List<LocalDateTime> result = new ArrayList<LocalDateTime>();
        LocalDateTime cursor = alignToNextSlot(startTime, intervalMinutes);
        while (!cursor.isAfter(endTime)) {
            result.add(cursor);
            cursor = cursor.plusMinutes(intervalMinutes);
        }
        return result;
    }

    /**
     * 构建返回给前端展示的每小时自然时刻列表。
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 每小时自然时刻列表
     */
    public List<LocalDateTime> buildHourlyTimeSlots(LocalDateTime startTime, LocalDateTime endTime) {
        return buildTimeSlots(startTime, endTime, 60);
    }

    /**
     * 计算时间槽数量。
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param intervalMinutes 步长
     * @return 时间槽数量
     */
    public long countTimeSlots(LocalDateTime startTime, LocalDateTime endTime, int intervalMinutes) {
        return buildTimeSlots(startTime, endTime, intervalMinutes).size();
    }

    /**
     * 向上对齐到最近的自然时间槽。
     *
     * @param time 原始时间
     * @param intervalMinutes 步长
     * @return 对齐后的时间
     */
    public LocalDateTime alignToNextSlot(LocalDateTime time, int intervalMinutes) {
        LocalDateTime minuteFloor = time.truncatedTo(ChronoUnit.MINUTES);
        int minuteOfDay = minuteFloor.getHour() * 60 + minuteFloor.getMinute();
        int remainder = minuteOfDay % intervalMinutes;
        LocalDateTime aligned = minuteFloor.minusMinutes(remainder);
        if (remainder != 0 || !minuteFloor.equals(time)) {
            aligned = aligned.plusMinutes(intervalMinutes);
        }
        return aligned;
    }
}
