export const referenceEventOptions = [
  { value: 'new_years_day', label: 'Neujahr' },
  { value: 'epiphany', label: 'Heilige Drei Könige' },
  { value: 'valentines_day', label: 'Valentinstag' },
  { value: 'womens_day', label: 'Internationaler Frauentag' },
  { value: 'carnival_monday', label: 'Rosenmontag' },
  { value: 'ash_wednesday', label: 'Aschermittwoch' },
  { value: 'palm_sunday', label: 'Palmsonntag' },
  { value: 'maundy_thursday', label: 'Gründonnerstag' },
  { value: 'good_friday', label: 'Karfreitag' },
  { value: 'easter_sunday', label: 'Ostersonntag' },
  { value: 'easter_monday', label: 'Ostermontag' },
  { value: 'may_day', label: 'Tag der Arbeit' },
  { value: 'ascension_day', label: 'Christi Himmelfahrt' },
  { value: 'pentecost_sunday', label: 'Pfingstsonntag' },
  { value: 'pentecost_monday', label: 'Pfingstmontag' },
  { value: 'corpus_christi', label: 'Fronleichnam' },
  { value: 'german_unity_day', label: 'Tag der Deutschen Einheit' },
  { value: 'halloween', label: 'Halloween' },
  { value: 'all_saints_day', label: 'Allerheiligen' },
  { value: 'st_nicholas_day', label: 'Nikolaus' },
  { value: 'christmas_eve', label: 'Heiligabend' },
  { value: 'christmas_day', label: '1. Weihnachtstag' },
  { value: 'boxing_day', label: '2. Weihnachtstag' },
  { value: 'new_years_eve', label: 'Silvester' }
];

const referenceEventLabelMap = referenceEventOptions.reduce((acc, entry) => {
  acc[entry.value] = entry.label;
  return acc;
}, {});

export const reminderUnitLabels = {
  days: 'Tage',
  weeks: 'Wochen',
  months: 'Monate'
};

export const reminderUnitSingular = {
  days: 'Tag',
  weeks: 'Woche',
  months: 'Monat'
};

function startOfDay(date) {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}

function addMonths(date, months) {
  const copy = new Date(date.getTime());
  copy.setMonth(copy.getMonth() + months);
  return copy;
}

function applyOffset(date, unit, value = 0) {
  const copy = new Date(date.getTime());
  const numericValue = Number(value) || 0;
  if (unit === 'weeks') {
    copy.setDate(copy.getDate() + numericValue * 7);
    return copy;
  }
  if (unit === 'months') {
    copy.setMonth(copy.getMonth() + numericValue);
    return copy;
  }
  copy.setDate(copy.getDate() + numericValue);
  return copy;
}

function subtractOffset(date, unit, value = 0) {
  return applyOffset(date, unit, -(Number(value) || 0));
}

function getEasterSunday(year) {
  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);
}

function getReferenceEventDate(eventKey, year) {
  if (eventKey === 'new_years_day') return new Date(year, 0, 1);
  if (eventKey === 'epiphany') return new Date(year, 0, 6);
  if (eventKey === 'valentines_day') return new Date(year, 1, 14);
  if (eventKey === 'womens_day') return new Date(year, 2, 8);
  if (eventKey === 'may_day') return new Date(year, 4, 1);
  if (eventKey === 'german_unity_day') return new Date(year, 9, 3);
  if (eventKey === 'halloween') return new Date(year, 9, 31);
  if (eventKey === 'all_saints_day') return new Date(year, 10, 1);
  if (eventKey === 'st_nicholas_day') return new Date(year, 11, 6);
  if (eventKey === 'christmas_eve') return new Date(year, 11, 24);
  if (eventKey === 'christmas_day') return new Date(year, 11, 25);
  if (eventKey === 'boxing_day') return new Date(year, 11, 26);
  if (eventKey === 'new_years_eve') return new Date(year, 11, 31);

  const easterSunday = getEasterSunday(year);
  const offsets = {
    carnival_monday: -48,
    ash_wednesday: -46,
    palm_sunday: -7,
    maundy_thursday: -3,
    good_friday: -2,
    easter_sunday: 0,
    easter_monday: 1,
    ascension_day: 39,
    pentecost_sunday: 49,
    pentecost_monday: 50,
    corpus_christi: 60
  };
  if (!(eventKey in offsets)) {
    return null;
  }
  return applyOffset(easterSunday, 'days', offsets[eventKey]);
}

export function getIntervalMonths(interval) {
  if (interval === 'monthly') {
    return 1;
  }
  if (interval === 'quarterly') {
    return 3;
  }
  return 12;
}

export function getReminderOffset(reminder = {}) {
  const unit = ['days', 'weeks', 'months'].includes(reminder?.beforeUnit) ? reminder.beforeUnit : 'days';
  const rawValue = Number(reminder?.beforeValue);
  const fallbackValue = Number(reminder?.daysBefore);
  const value = Number.isFinite(rawValue)
    ? Math.max(0, rawValue)
    : Number.isFinite(fallbackValue)
      ? Math.max(0, fallbackValue)
      : 6;
  return { unit, value };
}

export function getReminderReference(reminder = {}) {
  const reference = reminder?.reference;
  if (!reference || reference.mode !== 'event' || !referenceEventLabelMap[reference.eventKey]) {
    return {
      mode: 'pickupDate',
      eventKey: 'easter_sunday',
      occurrenceOffsetUnit: 'weeks',
      occurrenceOffsetValue: 0
    };
  }
  const unit = ['days', 'weeks', 'months'].includes(reference.occurrenceOffsetUnit)
    ? reference.occurrenceOffsetUnit
    : 'days';
  const value = Number.isFinite(Number(reference.occurrenceOffsetValue))
    ? Number(reference.occurrenceOffsetValue)
    : 0;
  return {
    mode: 'event',
    eventKey: reference.eventKey,
    occurrenceOffsetUnit: unit,
    occurrenceOffsetValue: value
  };
}

export function formatUnitLabel(unit, value) {
  const labels = value === 1 ? reminderUnitSingular : reminderUnitLabels;
  return `${value} ${labels[unit] || labels.days}`;
}

export function formatRelativeEventOffset(reference = {}) {
  const eventLabel = referenceEventLabelMap[reference.eventKey] || 'dem Referenz-Event';
  const unit = ['days', 'weeks', 'months'].includes(reference.occurrenceOffsetUnit)
    ? reference.occurrenceOffsetUnit
    : 'days';
  const value = Number(reference.occurrenceOffsetValue) || 0;
  if (value === 0) {
    return `am ${eventLabel}`;
  }
  const absValue = Math.abs(value);
  const offsetLabel = formatUnitLabel(unit, absValue);
  return value > 0 ? `${offsetLabel} nach ${eventLabel}` : `${offsetLabel} vor ${eventLabel}`;
}

export function formatReminderReference(reminder = {}) {
  const reference = getReminderReference(reminder);
  if (reference.mode !== 'event') {
    return 'gespeichertes Abholdatum';
  }
  return formatRelativeEventOffset(reference);
}

export function formatReminderOffset(reminder = {}) {
  const { unit, value } = getReminderOffset(reminder);
  return formatUnitLabel(unit, value);
}

export function formatReferenceLabel(reminder = {}) {
  return formatReminderReference(reminder);
}

export function subtractReminderOffset(date, reminder = {}) {
  const { unit, value } = getReminderOffset(reminder);
  return subtractOffset(date, unit, value);
}

export function getNextReminderSchedule(entry, today = new Date()) {
  if (!entry?.reminder?.enabled) {
    return null;
  }
  const todayStart = startOfDay(today);
  const reference = getReminderReference(entry.reminder);

  if (reference.mode === 'event') {
    for (let year = todayStart.getFullYear(); year <= todayStart.getFullYear() + 2; year += 1) {
      const eventDate = getReferenceEventDate(reference.eventKey, year);
      if (!eventDate) {
        return null;
      }
      const occurrence = startOfDay(
        applyOffset(eventDate, reference.occurrenceOffsetUnit, reference.occurrenceOffsetValue)
      );
      const reminderDate = startOfDay(subtractReminderOffset(occurrence, entry.reminder));
      if (reminderDate >= todayStart) {
        return { occurrence, reminderDate };
      }
    }
    return null;
  }

  if (!entry.pickupDate) {
    return null;
  }
  const baseDate = new Date(`${entry.pickupDate}T00:00:00`);
  if (Number.isNaN(baseDate.getTime())) {
    return null;
  }
  const intervalMonths = getIntervalMonths(entry.reminder.interval);
  let occurrence = startOfDay(baseDate);
  const guardYear = todayStart.getFullYear() + 200;
  while (occurrence < todayStart && occurrence.getFullYear() < guardYear) {
    occurrence = startOfDay(addMonths(occurrence, intervalMonths));
  }
  if (occurrence.getFullYear() >= guardYear) {
    return null;
  }
  let reminderDate = startOfDay(subtractReminderOffset(occurrence, entry.reminder));
  if (reminderDate < todayStart) {
    occurrence = startOfDay(addMonths(occurrence, intervalMonths));
    reminderDate = startOfDay(subtractReminderOffset(occurrence, entry.reminder));
  }
  return { occurrence, reminderDate };
}
