/**
 * ISO Week Calculation Utilities
 *
 * Helper functions for ISO 8601 week calculations
 * Week starts on Monday and ends on Sunday
 */

/**
 * Get the Monday of the ISO week for a given date
 */
export function getWeekStart(date: Date): Date {
  const d = new Date(date);
  const day = d.getDay();
  const diff = d.getDate() - day + (day === 0 ? -6 : 1);
  d.setDate(diff);
  d.setHours(0, 0, 0, 0);
  return d;
}

/**
 * Get the Sunday of the ISO week for a given date
 */
export function getWeekEnd(date: Date): Date {
  const monday = getWeekStart(date);
  const sunday = new Date(monday);
  sunday.setDate(sunday.getDate() + 6);
  sunday.setHours(23, 59, 59, 999);
  return sunday;
}

/**
 * Get ISO week number (1-53)
 */
export function getISOWeek(date: Date): number {
  const d = new Date(
    Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),
  );
  const dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}

/**
 * Format date as YYYY-MM-DD
 */
export function formatDate(date: Date): string {
  return date.toISOString().split("T")[0];
}

/**
 * Get all weeks in a date range
 */
export function getWeeksInRange(
  startDate: string,
  endDate: string,
): Array<{
  weekStart: string;
  weekEnd: string;
  weekNumber: number;
}> {
  const weeks: Array<{
    weekStart: string;
    weekEnd: string;
    weekNumber: number;
  }> = [];

  const start = new Date(startDate);
  const end = new Date(endDate);
  const current = getWeekStart(start);

  while (current <= end) {
    const weekStart = getWeekStart(current);
    const weekEnd = getWeekEnd(current);

    weeks.push({
      weekStart: formatDate(weekStart),
      weekEnd: formatDate(weekEnd),
      weekNumber: getISOWeek(current),
    });

    current.setDate(current.getDate() + 7);
  }

  return weeks;
}

/**
 * Test ISO week calculations
 */
export function testISOWeekCalculations(): void {
  console.log("ISO Week Calculation Tests\n");

  const testDates = [
    {
      date: "2024-01-01",
      expected: { monday: "2024-01-01", sunday: "2024-01-07", week: 1 },
    },
    {
      date: "2024-01-02",
      expected: { monday: "2024-01-01", sunday: "2024-01-07", week: 1 },
    },
    {
      date: "2024-01-07",
      expected: { monday: "2024-01-01", sunday: "2024-01-07", week: 1 },
    },
    {
      date: "2024-01-08",
      expected: { monday: "2024-01-08", sunday: "2024-01-14", week: 2 },
    },
    {
      date: "2024-12-31",
      expected: { monday: "2024-12-30", sunday: "2025-01-05", week: 1 },
    }, // Week 1 of 2025
  ];

  testDates.forEach(({ date, expected }) => {
    const d = new Date(date);
    const monday = formatDate(getWeekStart(d));
    const sunday = formatDate(getWeekEnd(d));
    const week = getISOWeek(d);

    const mondayMatch = monday === expected.monday;
    const sundayMatch = sunday === expected.sunday;
    const weekMatch = week === expected.week;

    console.log(`Date: ${date}`);
    console.log(
      `  Monday: ${monday} ${mondayMatch ? "✓" : "✗ (expected: " + expected.monday + ")"}`,
    );
    console.log(
      `  Sunday: ${sunday} ${sundayMatch ? "✓" : "✗ (expected: " + expected.sunday + ")"}`,
    );
    console.log(
      `  Week: ${week} ${weekMatch ? "✓" : "✗ (expected: " + expected.week + ")"}`,
    );
    console.log();
  });
}

// Run tests if executed directly
if (typeof require !== "undefined" && require.main === module) {
  testISOWeekCalculations();
}

export default {
  getWeekStart,
  getWeekEnd,
  getISOWeek,
  formatDate,
  getWeeksInRange,
  testISOWeekCalculations,
};
