type TimeSlot = { startTime: string; endTime: string };
type HasTimeSlots = { timeSlots: TimeSlot[] };

const toMinutes = (time: string) => {
  const [h, m] = time.split(':').map(Number);
  return h * 60 + m;
};

const slotsOverlap = (a: TimeSlot, b: TimeSlot) => {
  const aStart = toMinutes(a.startTime);
  const aEnd = toMinutes(a.endTime);
  const bStart = toMinutes(b.startTime);
  const bEnd = toMinutes(b.endTime);
  // Standard half-open interval overlap; touching ranges (one ends where the
  // other starts) are not considered overlapping.
  return aStart < bEnd && bStart < aEnd;
};

/**
 * Returns true if any time slot of `target` overlaps with any time slot of
 * any shift in `others`. Useful when we need to validate that a single shift
 * about to be added to a day does not collide with the shifts already on
 * that day.
 *
 * Note: comparisons are same-day only. Overnight shifts (end <= start) are
 * not handled.
 */
export const shiftOverlapsWithAny = (
  target: HasTimeSlots,
  others: HasTimeSlots[],
) => {
  for (const other of others) {
    for (const slotA of target.timeSlots) {
      for (const slotB of other.timeSlots) {
        if (slotsOverlap(slotA, slotB)) return true;
      }
    }
  }
  return false;
};
