import assert from "node:assert/strict"
import { describe, it } from "node:test"
import { describeRRule, expandOccurrences, parseRRule } from "./agenda-recurrence.ts"

const d = (iso: string) => new Date(iso)

describe("parseRRule", () => {
  it("parse une règle hebdomadaire avec BYDAY", () => {
    const rule = parseRRule("FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,TH")
    assert.deepEqual(rule, {
      freq: "WEEKLY",
      interval: 2,
      count: undefined,
      until: undefined,
      byday: [1, 4],
    })
  })

  it("rejette une fréquence inconnue", () => {
    assert.equal(parseRRule("FREQ=HOURLY"), null)
  })
})

describe("expandOccurrences", () => {
  it("développe une règle quotidienne dans la fenêtre", () => {
    const rule = parseRRule("FREQ=DAILY")!
    const out = expandOccurrences(
      d("2026-06-01T10:00:00"),
      rule,
      new Set(),
      d("2026-06-10T00:00:00"),
      d("2026-06-12T23:59:59"),
    )
    assert.deepEqual(out.map((x) => x.getDate()), [10, 11, 12])
  })

  it("respecte COUNT depuis la première occurrence", () => {
    const rule = parseRRule("FREQ=DAILY;COUNT=5")!
    const out = expandOccurrences(
      d("2026-06-01T10:00:00"),
      rule,
      new Set(),
      d("2026-06-04T00:00:00"),
      d("2026-06-30T23:59:59"),
    )
    // Occurrences 1–5 = 1er au 5 juin ; fenêtre depuis le 4 → 4 et 5 juin.
    assert.deepEqual(out.map((x) => x.getDate()), [4, 5])
  })

  it("respecte UNTIL", () => {
    const rule = parseRRule("FREQ=WEEKLY;UNTIL=20260615T000000Z")!
    const out = expandOccurrences(
      d("2026-06-01T10:00:00"),
      rule,
      new Set(),
      d("2026-06-01T00:00:00"),
      d("2026-07-31T23:59:59"),
    )
    assert.equal(out.length, 2) // 1er et 8 juin (15 juin 10:00 > UNTIL)
  })

  it("développe BYDAY hebdomadaire en gardant l'heure", () => {
    const rule = parseRRule("FREQ=WEEKLY;BYDAY=MO,WE")!
    // Lundi 1er juin 2026 à 09:30.
    const out = expandOccurrences(
      d("2026-06-01T09:30:00"),
      rule,
      new Set(),
      d("2026-06-01T00:00:00"),
      d("2026-06-07T23:59:59"),
    )
    assert.deepEqual(
      out.map((x) => [x.getDate(), x.getHours(), x.getMinutes()]),
      [
        [1, 9, 30],
        [3, 9, 30],
      ],
    )
  })

  it("exclut les EXDATE", () => {
    const rule = parseRRule("FREQ=DAILY")!
    const out = expandOccurrences(
      d("2026-06-01T10:00:00"),
      rule,
      new Set([d("2026-06-02T10:00:00").getTime()]),
      d("2026-06-01T00:00:00"),
      d("2026-06-03T23:59:59"),
    )
    assert.deepEqual(out.map((x) => x.getDate()), [1, 3])
  })

  it("ne produit aucune occurrence avant le début du master", () => {
    const rule = parseRRule("FREQ=WEEKLY;BYDAY=MO,FR")!
    // Master mercredi 3 juin 2026 → seul le vendredi 5 reste cette semaine-là.
    const out = expandOccurrences(
      d("2026-06-03T10:00:00"),
      rule,
      new Set(),
      d("2026-06-01T00:00:00"),
      d("2026-06-07T23:59:59"),
    )
    assert.deepEqual(out.map((x) => x.getDate()), [5])
  })
})

describe("describeRRule", () => {
  it("décrit les règles courantes", () => {
    assert.equal(describeRRule("FREQ=DAILY"), "Tous les jours")
    assert.equal(
      describeRRule("FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"),
      "Tous les jours ouvrés (lun.–ven.)",
    )
    assert.equal(describeRRule("FREQ=MONTHLY;INTERVAL=3"), "Tous les 3 mois")
  })
})
