(function () {
  function pad2(n) {
    return n < 10 ? '0' + n : String(n);
  }

  function formatDate(date) {
    return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
  }

  function parseDate(value) {
    const [y, m, d] = value.split('-').map(Number);
    return new Date(y, m - 1, d);
  }

  function getWeekStart(date) {
    const d = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    const day = d.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat
    const diff = (day + 6) % 7; // distance back to Monday
    d.setDate(d.getDate() - diff);
    return formatDate(d);
  }

  function getWeekDates(weekStart) {
    const start = parseDate(weekStart);
    const dates = [];
    for (let i = 0; i < 7; i++) {
      const d = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
      dates.push(formatDate(d));
    }
    return dates;
  }

  function addDays(date, days) {
    const d = parseDate(date);
    d.setDate(d.getDate() + days);
    return formatDate(d);
  }

  function timeToMinutes(value) {
    const [h, m] = value.split(':').map(Number);
    return h * 60 + m;
  }

  function minutesToTime(minutes) {
    const h = Math.floor(minutes / 60);
    const m = minutes % 60;
    return `${pad2(h)}:${pad2(m)}`;
  }

  function snapToSlot(value, slotMinutes) {
    const minutes = timeToMinutes(value);
    const snapped = Math.floor(minutes / slotMinutes) * slotMinutes;
    const clamped = Math.max(0, Math.min(24 * 60, snapped));
    return minutesToTime(clamped);
  }

  const exports_ = {
    formatDate,
    parseDate,
    getWeekStart,
    getWeekDates,
    addDays,
    timeToMinutes,
    minutesToTime,
    snapToSlot
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = exports_;
  }

  if (typeof window !== 'undefined') {
    window.dates = exports_;
  }
})();