import {
  Interval,
  addDays,
  clamp,
  differenceInMilliseconds,
  set,
} from 'date-fns';
import { fromZonedTime } from 'date-fns-tz';

/**
 * Generates an interval for the given time range for the baseDate, today by default. If the second time is lower than the first, the interval spans over to the next day
 * @param timeRange A user readable time range formatted as "HH:mm-HH:mm"
 */
export function generateIntervalForTimeRange(
  timeRange: string,
  timeZone = 'Europe/London',
  baseDate = new Date(),
): Interval {
  const [firstTime, secondTime] = timeRange.split('-');
  if (
    !firstTime ||
    !secondTime ||
    firstTime?.indexOf(':') === -1 ||
    secondTime?.indexOf(':') === -1
  ) {
    throw new Error(
      `Invalid argument for 'timeRange', expected format 'HH:mm-HH:mm', got ${timeRange}`,
    );
  }
  const [startHours, startMinutes] = firstTime.split(':').map((val) => +val);
  const [endHours, endMinutes] = secondTime.split(':').map((val) => +val);
  const startDate = baseDate;
  let endDate = baseDate;
  if (endHours < startHours) {
    endDate = addDays(endDate, 1);
  }
  return {
    start: fromZonedTime(
      set(startDate, {
        hours: startHours,
        minutes: startMinutes,
        seconds: 0,
        milliseconds: 0,
      }),
      timeZone,
    ),
    end: fromZonedTime(
      set(endDate, {
        hours: endHours,
        minutes: endMinutes,
        seconds: 0,
        milliseconds: 0,
      }),
      timeZone,
    ),
  };
}

export function clampInterval(
  interval: Interval,
  intervalClamp: Interval,
): Interval {
  return {
    start: clamp(interval.start, intervalClamp),
    end: clamp(interval.end, intervalClamp),
  };
}

export function getHoursInInterval(
  interval: Interval,
  intervalClamp?: Interval,
): number {
  const clampedInterval: Interval = clampInterval(
    interval,
    intervalClamp ?? interval,
  );

  return (
    differenceInMilliseconds(clampedInterval.end, clampedInterval.start) /
    60 /
    60 /
    1000
  );
}
