// every timestamp in this file is a number which contains an unix-timestamp-in-millisecond format,
// like returned by `new Date().getTime()`. this is needed because the "math"
// has to be done on integer numbers.

// we are trying to be compatible with
// https://github.com/grafana/loki/blob/089ec1b05f5ec15a8851d0e8230153e0eeb4dcec/pkg/querier/queryrange/split_by_interval.go#L327-L336

function expandTimeRange(startTime: number, endTime: number, step: number): [number, number] {
  // startTime is decreased to the closes multiple-of-step, if necessary
  const newStartTime = startTime - (startTime % step);

  // endTime is increased to the closed multiple-of-step, if necessary
  let newEndTime = endTime;
  const endStepMod = endTime % step;
  if (endStepMod !== 0) {
    newEndTime += step - endStepMod;
  }

  return [newStartTime, newEndTime];
}

export function splitTimeRange(
  startTime: number,
  endTime: number,
  step: number,
  idealRangeDuration: number
): Array<[number, number]> {
  if (idealRangeDuration < step) {
    // we cannot create chunks smaller than `step`
    return [[startTime, endTime]];
  }

  // we make the duration a multiple of `step`, lowering it if necessary
  const alignedDuration = Math.trunc(idealRangeDuration / step) * step;

  const [alignedStartTime, alignedEndTime] = expandTimeRange(startTime, endTime, step);

  const result: Array<[number, number]> = [];

  // we iterate it from the end, because we want to have the potentially smaller chunk at the end, not at the beginning
  for (let chunkEndTime = alignedEndTime; chunkEndTime > alignedStartTime; chunkEndTime -= alignedDuration + step) {
    // when we get close to the start of the time range, we need to be sure not
    // to cross over the startTime
    const chunkStartTime = Math.max(chunkEndTime - alignedDuration, alignedStartTime);
    result.push([chunkStartTime, chunkEndTime]);
  }

  // because we walked backwards, we need to reverse the array
  result.reverse();

  return result;
}
