/**
 * Feriados colombianos.
 *
 * Incluye:
 * - Fechas fijas (no se mueven)
 * - Fechas sujetas a Ley Emiliani (se trasladan al lunes siguiente)
 * - Fechas variables basadas en Pascua
 *
 * Para RUMBO esto se vuelve multi-país. Por ahora solo Colombia.
 */

interface HolidayDef {
  name: string
  /** Si true, si cae entre martes y domingo se mueve al lunes siguiente */
  emiliani: boolean
  /** Mes 1-12 */
  month: number
  /** Día 1-31 (solo si no es basado en Pascua) */
  day: number
  /** Offset desde Pascua en días (solo si es basado en Pascua) */
  easterOffset?: number
}

const HOLIDAY_DEFS: HolidayDef[] = [
  { name: 'Año Nuevo',              emiliani: false, month: 1,  day: 1  },
  { name: 'Reyes Magos',            emiliani: true,  month: 1,  day: 6  },
  { name: 'San José',               emiliani: true,  month: 3,  day: 19 },
  { name: 'Jueves Santo',           emiliani: false, month: 0,  day: 0, easterOffset: -3 },
  { name: 'Viernes Santo',          emiliani: false, month: 0,  day: 0, easterOffset: -2 },
  { name: 'Domingo de Pascua',      emiliani: false, month: 0,  day: 0, easterOffset: 0  },
  { name: 'Día del Trabajo',        emiliani: false, month: 5,  day: 1  },
  { name: 'Ascensión del Señor',    emiliani: true,  month: 0,  day: 0, easterOffset: 43 },
  { name: 'Corpus Christi',         emiliani: true,  month: 0,  day: 0, easterOffset: 64 },
  { name: 'Sagrado Corazón',        emiliani: true,  month: 0,  day: 0, easterOffset: 71 },
  { name: 'San Pedro y San Pablo',  emiliani: true,  month: 6,  day: 29 },
  { name: 'Día de la Independencia',emiliani: false, month: 7,  day: 20 },
  { name: 'Batalla de Boyacá',      emiliani: false, month: 8,  day: 7  },
  { name: 'Asunción de la Virgen',  emiliani: true,  month: 8,  day: 15 },
  { name: 'Día de la Raza',         emiliani: true,  month: 10, day: 12 },
  { name: 'Todos los Santos',       emiliani: true,  month: 11, day: 1  },
  { name: 'Indep. de Cartagena',    emiliani: true,  month: 11, day: 11 },
  { name: 'Inmaculada Concepción',  emiliani: false, month: 12, day: 8  },
  { name: 'Navidad',                emiliani: false, month: 12, day: 25 },
]

/**
 * Calcula la fecha de Pascua (Domingo de Resurrección) para un año dado.
 * Algoritmo de Butcher (Gregoriano).
 */
function easterSunday(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)
}

/**
 * Aplica la Ley Emiliani: si la fecha no cae en lunes, la mueve al lunes siguiente.
 */
function applyEmiliani(date: Date): Date {
  const dayOfWeek = date.getDay() // 0=dom, 1=lun, ..., 6=sáb
  if (dayOfWeek === 1) return date // ya es lunes
  const daysUntilMonday = (8 - dayOfWeek) % 7
  const result = new Date(date)
  result.setDate(result.getDate() + daysUntilMonday)
  return result
}

function dateFromDayMonth(year: number, month: number, day: number): Date {
  return new Date(year, month - 1, day)
}

export function getColombianHolidays(year: number): { date: Date; name: string }[] {
  const easter = easterSunday(year)
  const holidays: { date: Date; name: string }[] = []

  for (const def of HOLIDAY_DEFS) {
    let date: Date

    if (def.easterOffset !== undefined) {
      date = new Date(easter)
      date.setDate(date.getDate() + def.easterOffset)
    } else {
      date = dateFromDayMonth(year, def.month, def.day)
    }

    if (def.emiliani) {
      date = applyEmiliani(date)
    }

    // Solo agregar si no es domingo ya (los domingos siempre son no laborales)
    holidays.push({ date, name: def.name })
  }

  return holidays.sort((a, b) => a.date.getTime() - b.date.getTime())
}

export function isHoliday(date: Date): { holiday: boolean; name?: string } {
  const year = date.getFullYear()
  const holidays = getColombianHolidays(year)
  const found = holidays.find(h =>
    h.date.getFullYear() === date.getFullYear() &&
    h.date.getMonth() === date.getMonth() &&
    h.date.getDate() === date.getDate()
  )
  return found ? { holiday: true, name: found.name } : { holiday: false }
}

export function isWorkingDay(date: Date): boolean {
  const day = date.getDay()
  if (day === 0 || day === 6) return false
  return !isHoliday(date).holiday
}

export function addWorkingDays(date: Date, days: number): Date {
  const result = new Date(date)
  let added = 0
  while (added < days) {
    result.setDate(result.getDate() + 1)
    if (isWorkingDay(result)) added++
  }
  return result
}

export function nextWorkingDay(date: Date): Date {
  return addWorkingDays(date, 1)
}
