// ── Jours fériés statutaires du QUÉBEC — DÉTERMINISTE (pas d'IA : ce sont des règles fixes) ──
// Base = Loi sur les normes du travail (CNESST). 8 fériés. L'employeur peut AJOUTER des observances
// (lendemain, congé mobile…) via `extra`, et choisir Vendredi saint OU Lundi de Pâques.
// ⚠️ Tout en UTC pour éviter toute dérive de fuseau (les dates de fériés sont des jours civils).

// Dimanche de Pâques (algorithme de Meeus/Jones/Butcher).
function easterSunday (year) {
  const a = year % 19, b = Math.floor(year / 100), c = year % 100
  const d = Math.floor(b / 4), e = b % 4, f = Math.floor((b + 8) / 25)
  const g = Math.floor((b - f + 1) / 3), h = (19 * a + b - d - g + 15) % 30
  const i = Math.floor(c / 4), k = c % 4, 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) // 3 = mars, 4 = avril
  const day = ((h + l - 7 * m + 114) % 31) + 1
  return new Date(Date.UTC(year, month - 1, day))
}
// n-ième `weekday` (0=dim … 1=lun) du mois (month0 0-based).
function nthWeekday (year, month0, weekday, n) {
  const first = new Date(Date.UTC(year, month0, 1))
  const day = 1 + ((7 + weekday - first.getUTCDay()) % 7) + (n - 1) * 7
  return new Date(Date.UTC(year, month0, day))
}
const iso = (d) => d.toISOString().slice(0, 10)

// Liste des fériés QC pour une année. easterChoice: 'good_friday' (défaut) | 'easter_monday'.
function holidaysForYear (year, { easterChoice = 'good_friday', extra = [] } = {}) {
  const easter = easterSunday(year)
  const goodFriday = new Date(easter); goodFriday.setUTCDate(easter.getUTCDate() - 2)
  const easterMonday = new Date(easter); easterMonday.setUTCDate(easter.getUTCDate() + 1)
  // Journée nationale des patriotes = le LUNDI qui précède le 25 mai (donc lundi ≤ 24 mai).
  const patriotes = new Date(Date.UTC(year, 4, 24)); while (patriotes.getUTCDay() !== 1) patriotes.setUTCDate(patriotes.getUTCDate() - 1)
  const list = [
    { date: iso(new Date(Date.UTC(year, 0, 1))), name: "Jour de l'An" },
    { date: iso(easterChoice === 'easter_monday' ? easterMonday : goodFriday), name: easterChoice === 'easter_monday' ? 'Lundi de Pâques' : 'Vendredi saint' },
    { date: iso(patriotes), name: 'Journée nationale des patriotes' },
    { date: iso(new Date(Date.UTC(year, 5, 24))), name: 'Saint-Jean-Baptiste' },
    { date: iso(new Date(Date.UTC(year, 6, 1))), name: 'Fête du Canada' },
    { date: iso(nthWeekday(year, 8, 1, 1)), name: 'Fête du travail' }, // 1er lundi de septembre
    { date: iso(nthWeekday(year, 9, 1, 2)), name: 'Action de grâce' }, // 2e lundi d'octobre
    { date: iso(new Date(Date.UTC(year, 11, 25))), name: 'Noël' },
  ]
  for (const x of (extra || [])) if (x && x.date) list.push({ date: x.date, name: x.name || 'Congé', custom: true })
  return list.sort((p, q) => p.date.localeCompare(q.date))
}

// Fériés entre deux dates ISO (incluses), traversant les années.
function holidaysBetween (fromIso, toIso, opts = {}) {
  const y0 = parseInt(String(fromIso).slice(0, 4), 10); const y1 = parseInt(String(toIso).slice(0, 4), 10)
  const out = []
  for (let y = y0; y <= y1; y++) for (const h of holidaysForYear(y, opts)) if (h.date >= fromIso && h.date <= toIso) out.push(h)
  return out
}
function isHoliday (dateIso, opts = {}) {
  const y = parseInt(String(dateIso).slice(0, 4), 10)
  return holidaysForYear(y, opts).find(h => h.date === dateIso) || null
}

module.exports = { holidaysForYear, holidaysBetween, isHoliday, easterSunday }
