/**
 * Holiday detection service to provide hints for upcoming celebrations.
 */

interface Holiday {
    name: string;
    month: number; // 0-indexed (0 = Jan, 11 = Dec)
    day: number;
    description: string;
}

// Fixed-date holidays
const FIXED_HOLIDAYS: Holiday[] = [
    { name: 'New Year\'s Day', month: 0, day: 1, description: 'Happy New Year!' },
    { name: 'Valentine\'s Day', month: 1, day: 14, description: 'Love is in the air!' },
    { name: 'Halloween', month: 9, day: 31, description: 'Trick or treat!' },
    { name: 'Armistice Day', month: 10, day: 11, description: 'Lest we forget.' }, // Remembrance Day
    { name: 'Christmas Eve', month: 11, day: 24, description: 'Twas the night before Christmas...' },
    { name: 'Christmas Day', month: 11, day: 25, description: 'Merry Christmas!' },
    { name: 'Boxing Day', month: 11, day: 26, description: 'Happy Boxing Day!' },
    { name: 'New Year\'s Eve', month: 11, day: 31, description: 'Ring in the New Year!' },
];

/**
 * Calculates Easter Sunday for a given year using the Meeus/Jones/Butcher algorithm.
 */
function getEasterSunday(year: number): Date {
    const a = year % 19;
    const b = Math.floor(year / 100);
    const c = year % 100;
    const d = Math.floor(b / 4);
    const e = b % 4;
    const f = Math.floor((b + 8) / 25);
    const g = Math.floor((b - f + 1) / 3);
    const h = (19 * a + b - d - g + 15) % 30;
    const i = Math.floor(c / 4);
    const k = c % 4;
    const l = (32 + 2 * e + 2 * i - h - k) % 7;
    const m = Math.floor((a + 11 * h + 22 * l) / 451);
    const month = Math.floor((h + l - 7 * m + 114) / 31);
    const day = ((h + l - 7 * m + 114) % 31) + 1;
    return new Date(year, month - 1, day);
}

/**
 * Returns a hint if there is a major holiday or celebration in the week starting from weekStart.
 * A "week" is defined as 7 days from weekStart.
 */
export function getHolidayHint(weekStart: Date): string | null {
    const weekEnd = new Date(weekStart);
    weekEnd.setDate(weekEnd.getDate() + 7);

    const year = weekStart.getFullYear();

    // Check fixed holidays
    for (const holiday of FIXED_HOLIDAYS) {
        // Handle year boundaries for fixed holidays (e.g. looking at Jan 1 from Dec 28)
        const yearsToCheck = [year, year + 1];
        for (const y of yearsToCheck) {
            const holidayDate = new Date(y, holiday.month, holiday.day);
            if (holidayDate >= weekStart && holidayDate < weekEnd) {
                return `Hint: ${holiday.name} is coming up! ${holiday.description}`;
            }
        }
    }

    // Check variable holidays (Easter related)
    const easter = getEasterSunday(year);

    // Easter Sunday
    if (easter >= weekStart && easter < weekEnd) {
        return "Hint: Easter Sunday is this week! Happy Easter!";
    }

    // Good Friday (2 days before)
    const goodFriday = new Date(easter);
    goodFriday.setDate(goodFriday.getDate() - 2);
    if (goodFriday >= weekStart && goodFriday < weekEnd) {
        return "Hint: Good Friday is this week.";
    }

    // Easter Monday (1 day after)
    const easterMonday = new Date(easter);
    easterMonday.setDate(easterMonday.getDate() + 1);
    if (easterMonday >= weekStart && easterMonday < weekEnd) {
        return "Hint: Easter Monday is this week.";
    }

    return null;
}
