/**
 * UTC-safe week helpers.
 *
 * A "week" here is always Monday 00:00:00.000 UTC → Sunday 23:59:59.999 UTC.
 * All math is done on the UTC components of the Date so results never shift
 * because of the server's local timezone, and weeks correctly span across
 * month and year boundaries (e.g. Mon May 27 → Sun Jun 2).
 *
 * No external date library is used (the project has none installed), only the
 * native Date with its `*UTC*` accessors.
 */

/**
 * Returns the Monday 00:00:00.000 UTC that starts the week containing `date`.
 *
 * getUTCDay(): 0 = Sunday, 1 = Monday, ... 6 = Saturday.
 * To reach Monday we step back `day - 1` days, and Sunday (0) steps back 6.
 */
export function getWeekStart(date: Date): Date {
  // Strip the time part first, in UTC, so we don't drift across a day.
  const start = new Date(
    Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
  );

  const day = start.getUTCDay();
  const daysSinceMonday = day === 0 ? 6 : day - 1;

  start.setUTCDate(start.getUTCDate() - daysSinceMonday);
  start.setUTCHours(0, 0, 0, 0);
  return start;
}

/**
 * Returns the Sunday 23:59:59.999 UTC that ends the week containing `date`.
 * Always exactly 6 days after that week's Monday.
 */
export function getWeekEnd(date: Date): Date {
  const end = getWeekStart(date);
  end.setUTCDate(end.getUTCDate() + 6);
  end.setUTCHours(23, 59, 59, 999);
  return end;
}

/**
 * Returns the Monday that starts the week immediately before `weekStart`.
 * `weekStart` is expected to already be a Monday (as produced by getWeekStart).
 */
export function getPreviousWeekStart(weekStart: Date): Date {
  const prev = new Date(weekStart);
  prev.setUTCDate(prev.getUTCDate() - 7);
  prev.setUTCHours(0, 0, 0, 0);
  return prev;
}

/** Day names indexed by Date.getUTCDay() (0 = Sunday ... 6 = Saturday). */
const DAY_NAMES = [
  "Sunday",
  "Monday",
  "Tuesday",
  "Wednesday",
  "Thursday",
  "Friday",
  "Saturday",
];

/** Weekday name (in UTC) for a given date, e.g. "Monday". */
export function getDayName(date: Date): string {
  return DAY_NAMES[date.getUTCDay()];
}

/** Canonical `YYYY-MM-DD` key (UTC) used to look a date up in a day map. */
export function getDayKey(date: Date): string {
  return date.toISOString().slice(0, 10);
}

/**
 * ISO-8601 week number (1–53) for a date, in UTC. Weeks start on Monday and
 * week 1 is the week containing the first Thursday of the year — used for the
 * "W20", "W21" … bar-chart labels.
 */
export function getIsoWeek(date: Date): number {
  const d = new Date(
    Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
  );
  const day = d.getUTCDay() || 7; // treat Sunday (0) as 7
  d.setUTCDate(d.getUTCDate() + 4 - day); // shift to the week's Thursday
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}
