import { dateOf, isoDayOfWeek } from "@/lib/calendar"
import type { Locale, Translate } from "@/lib/i18n"
import { fullDay, monthAndYear } from "@/lib/i18n/dates"
import type { MessageKey } from "@/lib/i18n/messages"

/**
 * What the calendar tells a screen reader, in the reader's language.
 *
 * `react-day-picker` names every day cell, every column header and every
 * control itself, from the date-fns locale it falls back to when it is given
 * none. That locale is English, and it stayed English on both screens after the
 * visible chrome had been translated: a Thai reader saw 2569 and heard
 * "Sunday, April 26th, 2026". Two sources disagreeing is worse than one
 * missing, and the one nobody re-reads is the one only a screen reader speaks.
 *
 * Pure, with nothing under it, because the calendar is a client component and
 * what it imports it puts in the browser.
 *
 * **No ordinal anywhere.** Thai has no ordinal suffix and the visible chrome
 * dropped English's when it was translated, so a label saying "26th" would be
 * the calendar disagreeing with itself in the one language that has the form.
 */

/** 1 Monday to 7 Sunday, the numbering `isoDayOfWeek` answers in. */
const WEEKDAY_WORD: Record<number, MessageKey> = {
  1: "weekday.monday",
  2: "weekday.tuesday",
  3: "weekday.wednesday",
  4: "weekday.thursday",
  5: "weekday.friday",
  6: "weekday.saturday",
  7: "weekday.sunday",
}

/**
 * The picker's own `Date` as the `YYYY-MM-DD` day it stands for.
 *
 * Local fields and never `toISOString`, which would be a timezone away from the
 * day on the screen. /admin/holidays runs the picker in UTC, where these dates
 * are `TZDate`s whose getters already answer in that zone, so one reading
 * serves both screens and neither is shifted. It is the same conversion
 * `data-day` gets from the library, and those are correct.
 */
function day(date: Date): string {
  return dateOf(date.getFullYear(), date.getMonth() + 1, date.getDate())
}

/** Only the two the library composes into a day's name. */
type DayModifiers = { today?: boolean; selected?: boolean }

export function calendarLabels(locale: Locale, t: Translate) {
  /*
    Today first, then selected, so a day that is both reads "Today, Sunday, 26
    April 2026, selected" and not the other way round. That is the order the
    library composes them in, and the order the two Thai keys are written for.
  */
  const named = (date: Date, modifiers?: DayModifiers) => {
    const full = fullDay(day(date), locale)
    const today = modifiers?.today ? t("calendar.today", { day: full }) : full
    return modifiers?.selected ? t("calendar.selected", { day: today }) : today
  }

  return {
    labelDayButton: (date: Date, modifiers: DayModifiers) =>
      named(date, modifiers),
    /*
      The name on the cell itself, used instead of the button's when nothing is
      selectable. /admin/holidays is that case, and its cells carry no selection
      to announce, which is why this one only ever takes `today`.
    */
    labelGridcell: (date: Date, modifiers?: DayModifiers) =>
      named(date, { today: modifiers?.today }),
    labelGrid: (date: Date) => monthAndYear(day(date), locale),
    // The seven column headers, spoken in full where the screen shows one or
    // two letters. The same seven words the weekly duty is set with.
    labelWeekday: (date: Date) => t(WEEKDAY_WORD[isoDayOfWeek(day(date))]!),
    labelMonthDropdown: () => t("calendar.chooseMonth"),
    labelYearDropdown: () => t("calendar.chooseYear"),
    labelPrevious: () => t("calendar.previousMonth"),
    labelNext: () => t("calendar.nextMonth"),
    labelNav: () => t("calendar.navigation"),
    labelWeekNumber: (week: number) =>
      t("calendar.weekNumber", { number: week }),
    labelWeekNumberHeader: () => t("calendar.weekNumberHeader"),
  }
}
