import { describe, test, expect } from "bun:test";
import {
  addDaysISO,
  formatISODate,
  mondayOf,
  weekBucketsBetween,
} from "@/analytics/week-buckets.js";

const UTC = "UTC";

describe("formatISODate", () => {
  test("pads month and day", () => {
    expect(formatISODate(2026, 1, 5)).toBe("2026-01-05");
  });
  test("preserves two-digit month/day as-is", () => {
    expect(formatISODate(2026, 12, 31)).toBe("2026-12-31");
  });
});

describe("addDaysISO", () => {
  test("adds 7 days across a month boundary", () => {
    expect(addDaysISO("2026-03-30", 7)).toBe("2026-04-06");
  });
  test("adds 1 day at a year boundary", () => {
    expect(addDaysISO("2026-12-31", 1)).toBe("2027-01-01");
  });
  test("throws on malformed input", () => {
    expect(() => addDaysISO("not-a-date", 1)).toThrow();
  });
});

describe("mondayOf", () => {
  test("Wednesday resolves to the previous Monday", () => {
    // 2026-04-15 is a Wednesday in UTC.
    const wed = new Date("2026-04-15T12:00:00Z");
    expect(mondayOf(wed, UTC)).toBe("2026-04-13");
  });
  test("Monday resolves to itself", () => {
    const mon = new Date("2026-04-13T12:00:00Z");
    expect(mondayOf(mon, UTC)).toBe("2026-04-13");
  });
  test("Sunday resolves to the previous Monday (6 days back)", () => {
    const sun = new Date("2026-04-19T12:00:00Z");
    expect(mondayOf(sun, UTC)).toBe("2026-04-13");
  });
});

describe("weekBucketsBetween", () => {
  test("builds inclusive buckets covering start through end", () => {
    const start = new Date("2026-04-01T00:00:00Z"); // Wed — Monday-of is 2026-03-30
    const end = new Date("2026-04-15T00:00:00Z"); // Wed — Monday-of is 2026-04-13
    const buckets = weekBucketsBetween(start, end, UTC);
    expect(buckets).toEqual([
      { weekStart: "2026-03-30", weekEnd: "2026-04-06" },
      { weekStart: "2026-04-06", weekEnd: "2026-04-13" },
      { weekStart: "2026-04-13", weekEnd: "2026-04-20" },
    ]);
  });

  test("single-week span when start and end fall in the same ISO week", () => {
    const start = new Date("2026-04-14T00:00:00Z"); // Tue
    const end = new Date("2026-04-16T00:00:00Z"); // Thu
    const buckets = weekBucketsBetween(start, end, UTC);
    expect(buckets).toEqual([{ weekStart: "2026-04-13", weekEnd: "2026-04-20" }]);
  });

  test("empty when end precedes start", () => {
    const start = new Date("2026-04-15T00:00:00Z");
    const end = new Date("2026-04-01T00:00:00Z");
    expect(weekBucketsBetween(start, end, UTC)).toEqual([]);
  });

  test("buckets are contiguous (each weekEnd equals the next weekStart)", () => {
    const start = new Date("2026-01-01T00:00:00Z");
    const end = new Date("2026-03-31T00:00:00Z");
    const buckets = weekBucketsBetween(start, end, UTC);
    expect(buckets.length).toBeGreaterThan(4);
    for (let i = 1; i < buckets.length; i++) {
      expect(buckets[i]!.weekStart).toBe(buckets[i - 1]!.weekEnd);
    }
  });
});
