import { describe, expect, it } from "vitest";
import { isRecurringDay, getRecurringHoursForDay } from "../allocation/recurrence.js";
import { RecurrenceFrequency } from "@capakraken/shared";
import type { RecurrencePattern } from "@capakraken/shared";

const monday = new Date("2026-03-09"); // Monday
const tuesday = new Date("2026-03-10"); // Tuesday
const wednesday = new Date("2026-03-11"); // Wednesday
const friday = new Date("2026-03-13"); // Friday
const nextMonday = new Date("2026-03-16"); // Monday (next week)
const twoWeeksMonday = new Date("2026-03-23"); // Monday (two weeks after)

const allocationStart = new Date("2026-03-09"); // Monday

describe("isRecurringDay", () => {
  describe("WEEKLY", () => {
    const pattern: RecurrencePattern = {
      frequency: RecurrenceFrequency.WEEKLY,
      weekdays: [1, 3, 5], // Mon, Wed, Fri
    };

    it("returns true for days matching weekday list", () => {
      expect(isRecurringDay(monday, pattern, allocationStart)).toBe(true);
      expect(isRecurringDay(wednesday, pattern, allocationStart)).toBe(true);
      expect(isRecurringDay(friday, pattern, allocationStart)).toBe(true);
    });

    it("returns false for days not in weekday list", () => {
      expect(isRecurringDay(tuesday, pattern, allocationStart)).toBe(false);
    });
  });

  describe("BIWEEKLY", () => {
    const pattern: RecurrencePattern = {
      frequency: RecurrenceFrequency.BIWEEKLY,
      weekdays: [1], // Monday only
      interval: 2,
    };

    it("returns true on the allocation start week (week 0)", () => {
      expect(isRecurringDay(monday, pattern, allocationStart)).toBe(true);
    });

    it("returns false on the next week (week 1, odd)", () => {
      expect(isRecurringDay(nextMonday, pattern, allocationStart)).toBe(false);
    });

    it("returns true two weeks after start (week 2, even)", () => {
      expect(isRecurringDay(twoWeeksMonday, pattern, allocationStart)).toBe(true);
    });

    it("returns false for non-matching weekdays even in active weeks", () => {
      expect(isRecurringDay(tuesday, pattern, allocationStart)).toBe(false);
    });
  });

  describe("MONTHLY", () => {
    const pattern: RecurrencePattern = {
      frequency: RecurrenceFrequency.MONTHLY,
      monthDay: 15,
    };

    it("returns true on the specified day of month", () => {
      expect(isRecurringDay(new Date("2026-03-15"), pattern, allocationStart)).toBe(true);
    });

    it("returns false on other days", () => {
      expect(isRecurringDay(new Date("2026-03-14"), pattern, allocationStart)).toBe(false);
    });

    it("returns false when monthDay is undefined", () => {
      const noDay: RecurrencePattern = {
        frequency: RecurrenceFrequency.MONTHLY,
      };
      expect(isRecurringDay(new Date("2026-03-15"), noDay, allocationStart)).toBe(false);
    });
  });

  describe("CUSTOM", () => {
    const pattern: RecurrencePattern = {
      frequency: RecurrenceFrequency.CUSTOM,
    };

    it("always returns true", () => {
      expect(isRecurringDay(monday, pattern, allocationStart)).toBe(true);
      expect(isRecurringDay(tuesday, pattern, allocationStart)).toBe(true);
    });
  });
});

describe("getRecurringHoursForDay", () => {
  const weeklyPattern: RecurrencePattern = {
    frequency: RecurrenceFrequency.WEEKLY,
    weekdays: [1, 3, 5], // Mon, Wed, Fri
  };

  it("returns default hours on recurring days", () => {
    expect(getRecurringHoursForDay(monday, weeklyPattern, 8, allocationStart)).toBe(8);
  });

  it("returns 0 on non-recurring days", () => {
    expect(getRecurringHoursForDay(tuesday, weeklyPattern, 8, allocationStart)).toBe(0);
  });

  it("uses pattern.hoursPerDay when set", () => {
    const patternWithHours: RecurrencePattern = {
      ...weeklyPattern,
      hoursPerDay: 4,
    };
    expect(getRecurringHoursForDay(monday, patternWithHours, 8, allocationStart)).toBe(4);
  });

  it("returns 0 before pattern startDate", () => {
    const patternWithStart: RecurrencePattern = {
      ...weeklyPattern,
      startDate: "2026-03-16",
    };
    expect(getRecurringHoursForDay(monday, patternWithStart, 8, allocationStart)).toBe(0);
  });

  it("returns 0 after pattern endDate", () => {
    const patternWithEnd: RecurrencePattern = {
      ...weeklyPattern,
      endDate: "2026-03-08",
    };
    expect(getRecurringHoursForDay(monday, patternWithEnd, 8, allocationStart)).toBe(0);
  });

  it("returns hours within pattern date bounds", () => {
    const bounded: RecurrencePattern = {
      ...weeklyPattern,
      startDate: "2026-03-01",
      endDate: "2026-03-31",
    };
    expect(getRecurringHoursForDay(monday, bounded, 8, allocationStart)).toBe(8);
  });
});
