import { describe, expect, it } from "vitest";
import { isVacationDay, getVacationDatesInRange } from "../vacation/utils.js";
import type { VacationRange } from "../vacation/utils.js";

const approved = (start: string, end: string): VacationRange => ({
  startDate: new Date(start),
  endDate: new Date(end),
  status: "APPROVED",
});

const pending = (start: string, end: string): VacationRange => ({
  startDate: new Date(start),
  endDate: new Date(end),
  status: "PENDING",
});

describe("isVacationDay", () => {
  it("returns true when date falls within an approved vacation", () => {
    const vacations = [approved("2026-03-10", "2026-03-14")];
    expect(isVacationDay(new Date("2026-03-12"), vacations)).toBe(true);
  });

  it("returns true on the start date of the vacation", () => {
    const vacations = [approved("2026-03-10", "2026-03-14")];
    expect(isVacationDay(new Date("2026-03-10"), vacations)).toBe(true);
  });

  it("returns true on the end date of the vacation", () => {
    const vacations = [approved("2026-03-10", "2026-03-14")];
    expect(isVacationDay(new Date("2026-03-14"), vacations)).toBe(true);
  });

  it("returns false when date is outside vacation range", () => {
    const vacations = [approved("2026-03-10", "2026-03-14")];
    expect(isVacationDay(new Date("2026-03-09"), vacations)).toBe(false);
    expect(isVacationDay(new Date("2026-03-15"), vacations)).toBe(false);
  });

  it("ignores non-APPROVED vacations", () => {
    const vacations = [pending("2026-03-10", "2026-03-14")];
    expect(isVacationDay(new Date("2026-03-12"), vacations)).toBe(false);
  });

  it("returns false for empty vacation array", () => {
    expect(isVacationDay(new Date("2026-03-12"), [])).toBe(false);
  });

  it("handles multiple overlapping vacations", () => {
    const vacations = [
      approved("2026-03-10", "2026-03-12"),
      approved("2026-03-11", "2026-03-14"),
    ];
    expect(isVacationDay(new Date("2026-03-11"), vacations)).toBe(true);
    expect(isVacationDay(new Date("2026-03-13"), vacations)).toBe(true);
  });

  it("handles mixed statuses correctly", () => {
    const vacations = [
      pending("2026-03-10", "2026-03-14"),
      approved("2026-03-20", "2026-03-21"),
    ];
    expect(isVacationDay(new Date("2026-03-12"), vacations)).toBe(false);
    expect(isVacationDay(new Date("2026-03-20"), vacations)).toBe(true);
  });
});

describe("getVacationDatesInRange", () => {
  it("returns approved vacation dates within range", () => {
    const vacations = [approved("2026-03-10", "2026-03-12")];
    const dates = getVacationDatesInRange(
      new Date("2026-03-09"),
      new Date("2026-03-13"),
      vacations,
    );
    expect(dates).toHaveLength(3); // 10, 11, 12
    expect(dates[0]!.getDate()).toBe(10);
    expect(dates[2]!.getDate()).toBe(12);
  });

  it("clips to the query range", () => {
    const vacations = [approved("2026-03-05", "2026-03-15")];
    const dates = getVacationDatesInRange(
      new Date("2026-03-10"),
      new Date("2026-03-12"),
      vacations,
    );
    expect(dates).toHaveLength(3); // 10, 11, 12
  });

  it("returns empty for no approved vacations", () => {
    const vacations = [pending("2026-03-10", "2026-03-14")];
    const dates = getVacationDatesInRange(
      new Date("2026-03-01"),
      new Date("2026-03-31"),
      vacations,
    );
    expect(dates).toEqual([]);
  });

  it("handles multiple non-overlapping vacations", () => {
    const vacations = [
      approved("2026-03-10", "2026-03-11"),
      approved("2026-03-20", "2026-03-21"),
    ];
    const dates = getVacationDatesInRange(
      new Date("2026-03-01"),
      new Date("2026-03-31"),
      vacations,
    );
    expect(dates).toHaveLength(4); // 10, 11, 20, 21
  });

  it("returns empty when range does not intersect vacations", () => {
    const vacations = [approved("2026-04-01", "2026-04-05")];
    const dates = getVacationDatesInRange(
      new Date("2026-03-01"),
      new Date("2026-03-31"),
      vacations,
    );
    expect(dates).toEqual([]);
  });
});
