// src/utils/holidays.ts
// US Federal Holidays utility

export interface Holiday {
    date: string; // YYYY-MM-DD format
    name: string;
}

/**
 * Calculate US Federal Holidays for a given year
 */
export function getFederalHolidays(year: number): Holiday[] {
    const holidays: Holiday[] = [];

    // Fixed date holidays
    holidays.push({ date: `${year}-01-01`, name: "New Year's Day" });
    holidays.push({ date: `${year}-07-04`, name: "Independence Day" });
    holidays.push({ date: `${year}-11-11`, name: "Veterans Day" });
    holidays.push({ date: `${year}-12-25`, name: "Christmas Day" });

    // Martin Luther King Jr. Day - 3rd Monday in January
    holidays.push({ date: getNthWeekdayOfMonth(year, 0, 1, 3), name: "Martin Luther King Jr. Day" });

    // Presidents' Day - 3rd Monday in February
    holidays.push({ date: getNthWeekdayOfMonth(year, 1, 1, 3), name: "Presidents' Day" });

    // Memorial Day - Last Monday in May
    holidays.push({ date: getLastWeekdayOfMonth(year, 4, 1), name: "Memorial Day" });

    // Juneteenth - June 19
    holidays.push({ date: `${year}-06-19`, name: "Juneteenth" });

    // Labor Day - 1st Monday in September
    holidays.push({ date: getNthWeekdayOfMonth(year, 8, 1, 1), name: "Labor Day" });

    // Columbus Day - 2nd Monday in October
    holidays.push({ date: getNthWeekdayOfMonth(year, 9, 1, 2), name: "Columbus Day" });

    // Thanksgiving - 4th Thursday in November
    holidays.push({ date: getNthWeekdayOfMonth(year, 10, 4, 4), name: "Thanksgiving Day" });

    return holidays;
}

/**
 * Get the nth occurrence of a weekday in a month
 * @param year - Year
 * @param month - Month (0-11)
 * @param weekday - Day of week (0=Sunday, 1=Monday, etc.)
 * @param n - Which occurrence (1=first, 2=second, etc.)
 */
function getNthWeekdayOfMonth(year: number, month: number, weekday: number, n: number): string {
    const firstDay = new Date(year, month, 1);
    const firstWeekday = firstDay.getDay();

    // Calculate days until the first occurrence of the target weekday
    let daysUntilWeekday = (weekday - firstWeekday + 7) % 7;

    // Calculate the date of the nth occurrence
    const targetDate = 1 + daysUntilWeekday + (n - 1) * 7;

    const date = new Date(year, month, targetDate);
    return formatDate(date);
}

/**
 * Get the last occurrence of a weekday in a month
 * @param year - Year
 * @param month - Month (0-11)
 * @param weekday - Day of week (0=Sunday, 1=Monday, etc.)
 */
function getLastWeekdayOfMonth(year: number, month: number, weekday: number): string {
    // Start from the last day of the month and work backwards
    const lastDay = new Date(year, month + 1, 0);
    const lastDayOfWeek = lastDay.getDay();

    // Calculate days to subtract to get to the target weekday
    let daysToSubtract = (lastDayOfWeek - weekday + 7) % 7;

    const date = new Date(year, month, lastDay.getDate() - daysToSubtract);
    return formatDate(date);
}

/**
 * Format date as YYYY-MM-DD
 */
function formatDate(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}

/**
 * Get holidays for a date range
 */
export function getHolidaysForRange(startDate: Date, endDate: Date): Holiday[] {
    const startYear = startDate.getFullYear();
    const endYear = endDate.getFullYear();

    const allHolidays: Holiday[] = [];

    for (let year = startYear; year <= endYear; year++) {
        allHolidays.push(...getFederalHolidays(year));
    }

    // Filter to only holidays in the date range
    return allHolidays.filter(holiday => {
        const holidayDate = new Date(holiday.date);
        return holidayDate >= startDate && holidayDate <= endDate;
    });
}

/**
 * Check if a date is a federal holiday
 */
export function isHoliday(date: string, holidays: Holiday[]): boolean {
    return holidays.some(holiday => holiday.date === date);
}

/**
 * Get holiday name for a date
 */
export function getHolidayName(date: string, holidays: Holiday[]): string | null {
    const holiday = holidays.find(h => h.date === date);
    return holiday ? holiday.name : null;
}
