import { describe, expect, test } from "bun:test"

import { translator, type Locale } from "@/lib/i18n"
import { calendarLabels } from "@/lib/i18n/calendar-labels"

function labels(locale: Locale) {
  return calendarLabels(locale, translator(locale))
}

/** A Sunday, chosen because it is the shape the defect was reported in. */
const SUNDAY = new Date(2026, 3, 26)

describe("labelDayButton", () => {
  test("a Thai reader is told the Buddhist year", () => {
    expect(labels("th").labelDayButton(SUNDAY, {})).toBe(
      "วันอาทิตย์ที่ 26 เมษายน 2569",
    )
  })

  /**
   * The defect itself. The visible grid said 2569 in Thai and the accessible
   * name said "Sunday, April 26th, 2026", so the two disagreed on the year, the
   * language and the number.
   */
  test("no English and no ordinal reaches a Thai reader", () => {
    const label = labels("th").labelDayButton(SUNDAY, {
      today: true,
      selected: true,
    })
    expect(label).not.toMatch(/[A-Za-z]/)
    expect(label).not.toContain("2026")
    expect(label).not.toMatch(/\d(st|nd|rd|th)/)
  })

  test("an English reader keeps a date with no ordinal in it", () => {
    expect(labels("en").labelDayButton(SUNDAY, {})).toBe(
      "Sunday, 26 April 2026",
    )
  })

  test("today wraps the date and selected follows it", () => {
    const en = labels("en")
    expect(en.labelDayButton(SUNDAY, { today: true })).toBe(
      "Today, Sunday, 26 April 2026",
    )
    expect(en.labelDayButton(SUNDAY, { selected: true })).toBe(
      "Sunday, 26 April 2026, selected",
    )
    expect(en.labelDayButton(SUNDAY, { today: true, selected: true })).toBe(
      "Today, Sunday, 26 April 2026, selected",
    )
  })

  test("the Thai affixes go where Thai puts them", () => {
    const th = labels("th")
    expect(th.labelDayButton(SUNDAY, { today: true })).toBe(
      "วันนี้ วันอาทิตย์ที่ 26 เมษายน 2569",
    )
    expect(th.labelDayButton(SUNDAY, { selected: true })).toBe(
      "วันอาทิตย์ที่ 26 เมษายน 2569 เลือกอยู่",
    )
  })
})

describe("labelGridcell", () => {
  /**
   * /admin/holidays selects nothing, so the library names the cell instead of a
   * button. Nothing there is selected and saying so would announce a state the
   * screen does not have.
   */
  test("it says today and never says selected", () => {
    expect(
      labels("en").labelGridcell(SUNDAY, { today: true, selected: true }),
    ).toBe("Today, Sunday, 26 April 2026")
  })
})

describe("the rest of the chrome", () => {
  test("the grid is announced as the month it holds", () => {
    expect(labels("en").labelGrid(SUNDAY)).toBe("April 2026")
    expect(labels("th").labelGrid(SUNDAY)).toBe("เมษายน 2569")
  })

  test("a column header is the weekday in full", () => {
    expect(labels("en").labelWeekday(SUNDAY)).toBe("Sunday")
    expect(labels("th").labelWeekday(SUNDAY)).toBe("วันอาทิตย์")
    // Monday, the other end of `isoDayOfWeek`.
    expect(labels("th").labelWeekday(new Date(2026, 3, 27))).toBe("วันจันทร์")
  })

  test("every control has a Thai name", () => {
    const th = labels("th")
    for (const label of [
      th.labelMonthDropdown(),
      th.labelYearDropdown(),
      th.labelPrevious(),
      th.labelNext(),
      th.labelNav(),
      th.labelWeekNumber(18),
      th.labelWeekNumberHeader(),
    ]) {
      expect(label).not.toBe("")
      expect(label).not.toMatch(/[A-Za-z]/)
    }
  })
})

/**
 * /admin/holidays runs the picker in UTC and /admin/recurrence in the machine's
 * own zone. A day read off the wrong fields lands a date either side of
 * midnight on one of them, which is exactly the mistake `lib/calendar.ts` was
 * written to stop.
 */
describe("the day a Date stands for", () => {
  test("it is the day on the face of it, not the day in UTC", () => {
    const lateEvening = new Date(2026, 3, 26, 23, 30)
    expect(labels("en").labelDayButton(lateEvening, {})).toBe(
      "Sunday, 26 April 2026",
    )
    const earlyMorning = new Date(2026, 3, 26, 0, 30)
    expect(labels("en").labelDayButton(earlyMorning, {})).toBe(
      "Sunday, 26 April 2026",
    )
  })
})
