// Maps any date to one of the 52 canonical temporal-propers ids already
// authored in data/propers/temporal/*.yml — the "which Sunday's collect
// governs this date" question. A feria always inherits the collect of the
// Sunday on or before it (real rubric: the ferias of a week use that
// week's own Sunday collect), so this is really "find the governing
// Sunday, then name it."
//
// Deliberately Pentecost/offset-based, not Trinity-counted — this is
// content-storage identity, kept independent of whatever counting
// convention calendar/day-label.ts displays on screen. See that file's
// header and propers/index.ts's getTemporalProper for the fuller version
// of this reasoning.
//
// One known, deliberately unfixed gap: the ferias between Christmas Day
// and the Sunday within its octave, and between Epiphany and its own
// first Sunday, fall back to that season's first named Sunday a few days
// early — Christmas Day's and Epiphany's own collects aren't authored as
// separate temporal-propers entries (only Sunday collects were pulled), so
// this is a deliberate approximation, not an oversight.
//
// Overflow years (Easter early enough that fewer than 6 Sundays after
// Epiphany occur before Septuagesima cuts in) are handled below: the
// skipped post-Epiphany Sundays "resume" after Sunday XXIII after
// Pentecost, in their own numeric order, right before the fixed final
// Sunday of the year (always Sunday XXIV's own formulary, regardless of
// how many Sundays actually elapsed since Pentecost). Ported directly
// from the reference engine's own `getweek()`
// (DivinumOfficium/Date.pm) — same rubric, same arithmetic (weeks-until-
// Advent, not a separately-tracked count of skipped Epiphany Sundays);
// confirmed against that source rather than re-derived by hand.
import { resolveSeason, sundayOnOrBefore, firstSundayStrictlyAfter, adventStart, easterOffsetOf } from './temporal';
import { daysBetween } from './date-math';

const EASTER_OFFSET_IDS: [number, string][] = [
  [-63, 'septuagesima'],
  [-56, 'sexagesima'],
  [-49, 'quinquagesima'],
  [-42, 'lent-1'],
  [-35, 'lent-2'],
  [-28, 'lent-3'],
  [-21, 'lent-4'],
  [-14, 'passion-sunday'],
  [-7, 'palm-sunday'],
  [0, 'easter-sunday'],
  [7, 'easter-octave'],
  [14, 'easter-3'],
  [21, 'easter-4'],
  [28, 'easter-5'],
  [35, 'easter-6'],
  [42, 'sunday-after-ascension'],
  [49, 'pentecost-sunday'],
];
// Sundays I-XXII after Pentecost only — XXIII and XXIV are handled by
// resolvePostPentecost23Plus below, since (unlike I-XXII) which id a given
// week gets can depend on distance-to-Advent, not just its own offset.
for (let n = 1; n <= 22; n++) {
  EASTER_OFFSET_IDS.push([56 + 7 * (n - 1), `post-pentecost-${String(n).padStart(2, '0')}`]);
}
const EASTER_OFFSET_ID_MAP = new Map(EASTER_OFFSET_IDS);

/**
 * A governing Sunday at or beyond Pentecost week XXIII. `pentecostWeek` is
 * the reference engine's own `$n` (1 = Trinity Sunday, verified against
 * DivinumOfficium/Date.pm and its Tempora/PentNN file naming).
 */
function resolvePostPentecost23Plus(governingSunday: string, year: number, pentecostWeek: number): string {
  const wdist = Math.floor((daysBetween(governingSunday, adventStart(year)) + 6) / 7);
  if (wdist < 2) {
    return 'post-pentecost-24';
  }
  if (pentecostWeek === 23) {
    return 'post-pentecost-23';
  }
  return `post-epiphany-${8 - wdist}`;
}

export function resolveTemporalId(isoDate: string): string {
  const season = resolveSeason(isoDate);
  const year = Number(isoDate.slice(0, 4));

  // The Vigil of Christmas (Dec 24) has its own real proper content
  // (collect, Lauds antiphons, Matins Gospel+homily nocturn) distinct from
  // Advent 4's own — see data/propers/temporal/vigil-of-christmas-collect.yml
  // and data/propers/nocturn-readings/vigil-of-christmas.yml, both
  // transcribed directly from the reference engine's Sancti/12-24.txt.
  // Applies even when Dec 24 itself is Advent 4's own Sunday — per direct
  // instruction (2026-08), the Vigil's own identity (rank/collect/Lauds
  // antiphons) governs that day too, with Advent 4 folded in as a
  // commemoration instead (calendar/index.ts's
  // applyAdventFourVigilCommemoration) rather than the reference engine's
  // own `no commemoratio` rule. Matins' three-nocturn Sunday psalmody is
  // unaffected either way — it's driven by `day.weekday`, not by this id
  // (hours/matins.ts's own `threeNocturns` check), so Advent 4's "Psalmi
  // Dominica" standing survives this id swap for free.
  if (isoDate.slice(5) === '12-24') {
    return 'vigil-of-christmas';
  }

  if (season === 'advent') {
    const start = adventStart(year);
    const n = Math.round(daysBetween(start, sundayOnOrBefore(isoDate)) / 7) + 1;
    return `advent-${Math.min(n, 4)}`;
  }

  if (season === 'christmastide') {
    return 'christmas-octave-sunday';
  }

  if (season === 'epiphanytide') {
    const firstSunday = firstSundayStrictlyAfter(`${year}-01-06`);
    if (isoDate < firstSunday) {
      return 'post-epiphany-1';
    }
    const n = Math.round(daysBetween(firstSunday, sundayOnOrBefore(isoDate)) / 7) + 1;
    return `post-epiphany-${Math.min(n, 6)}`;
  }

  // Everything else (Septuagesima-tide through Trinitytide) is Easter-
  // anchored — find the governing Sunday and map its own offset directly,
  // regardless of which `season` bucket the feria itself falls in (the
  // ferias right after Ash Wednesday genuinely reuse Quinquagesima's
  // collect, crossing what resolveSeason calls two different seasons).
  const governingSunday = sundayOnOrBefore(isoDate);
  const offset = easterOffsetOf(governingSunday);
  const pentecostWeek = Math.round((offset - 49) / 7);
  if (pentecostWeek >= 23) {
    return resolvePostPentecost23Plus(governingSunday, year, pentecostWeek);
  }
  return EASTER_OFFSET_ID_MAP.get(offset) ?? 'septuagesima';
}
