import { describe, it, expect } from "vitest";
import { calculateSAH, getDailyHours } from "../sah/calculator.js";
import type { SpainScheduleRule } from "@capakraken/shared";

const spainRules: SpainScheduleRule = {
  type: "spain",
  fridayHours: 6.5,
  summerPeriod: { from: "07-01", to: "09-15" },
  summerHours: 6.5,
  regularHours: 9,
};

describe("getDailyHours", () => {
  it("returns base hours when no schedule rules", () => {
    expect(getDailyHours(new Date("2026-03-10"), 8)).toBe(8); // Monday
    expect(getDailyHours(new Date("2026-03-13"), 9)).toBe(9); // Thursday
  });

  it("returns Spain friday hours", () => {
    // 2026-03-13 is a Friday
    expect(getDailyHours(new Date("2026-03-13"), 8, spainRules)).toBe(6.5);
  });

  it("returns Spain summer hours Mon-Thu", () => {
    // 2026-07-06 is a Monday in summer
    expect(getDailyHours(new Date("2026-07-06"), 8, spainRules)).toBe(6.5);
  });

  it("returns Spain regular hours Mon-Thu outside summer", () => {
    // 2026-03-09 is a Monday, not summer
    expect(getDailyHours(new Date("2026-03-09"), 8, spainRules)).toBe(9);
  });
});

describe("calculateSAH", () => {
  it("calculates basic SAH for a full-time German employee in one week", () => {
    // 2026-03-09 (Mon) to 2026-03-13 (Fri) — 5 working days, no holidays
    const result = calculateSAH({
      dailyWorkingHours: 8,
      fte: 1.0,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: [],
    });
    expect(result.calendarDays).toBe(5);
    expect(result.weekendDays).toBe(0);
    expect(result.grossWorkingDays).toBe(5);
    expect(result.netWorkingDays).toBe(5);
    expect(result.standardAvailableHours).toBe(40);
  });

  it("reduces hours by FTE factor", () => {
    const result = calculateSAH({
      dailyWorkingHours: 8,
      fte: 0.5,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: [],
    });
    expect(result.standardAvailableHours).toBe(20);
    expect(result.effectiveHoursPerDay).toBe(4);
  });

  it("deducts public holidays", () => {
    const result = calculateSAH({
      dailyWorkingHours: 8,
      fte: 1.0,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: ["2026-03-10"], // Tuesday is holiday
      absenceDays: [],
    });
    expect(result.publicHolidayDays).toBe(1);
    expect(result.netWorkingDays).toBe(4);
    expect(result.standardAvailableHours).toBe(32);
  });

  it("deducts absence days", () => {
    const result = calculateSAH({
      dailyWorkingHours: 8,
      fte: 1.0,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: ["2026-03-11", "2026-03-12"], // Wed + Thu
    });
    expect(result.absenceDays).toBe(2);
    expect(result.netWorkingDays).toBe(3);
    expect(result.standardAvailableHours).toBe(24);
  });

  it("handles weekends correctly", () => {
    // 2026-03-07 (Sat) to 2026-03-13 (Fri) — includes a full weekend
    const result = calculateSAH({
      dailyWorkingHours: 8,
      fte: 1.0,
      periodStart: new Date("2026-03-07"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: [],
    });
    expect(result.calendarDays).toBe(7);
    expect(result.weekendDays).toBe(2);
    expect(result.grossWorkingDays).toBe(5);
    expect(result.netWorkingDays).toBe(5);
    expect(result.standardAvailableHours).toBe(40);
  });

  it("uses 9h for India", () => {
    const result = calculateSAH({
      dailyWorkingHours: 9,
      fte: 1.0,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: [],
    });
    expect(result.standardAvailableHours).toBe(45);
  });

  it("handles Spain variable schedule in summer", () => {
    // 2026-07-06 (Mon) to 2026-07-10 (Fri) — all summer, includes Friday
    const result = calculateSAH({
      dailyWorkingHours: 8,
      scheduleRules: spainRules,
      fte: 1.0,
      periodStart: new Date("2026-07-06"),
      periodEnd: new Date("2026-07-10"),
      publicHolidays: [],
      absenceDays: [],
    });
    // Mon-Fri all summer: 6.5 * 5 = 32.5
    expect(result.standardAvailableHours).toBe(32.5);
  });

  it("handles Spain variable schedule outside summer", () => {
    // 2026-03-09 (Mon) to 2026-03-13 (Fri) — non-summer
    const result = calculateSAH({
      dailyWorkingHours: 8,
      scheduleRules: spainRules,
      fte: 1.0,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: [],
    });
    // Mon-Thu: 9h each = 36, Fri: 6.5h = total 42.5
    expect(result.standardAvailableHours).toBe(42.5);
  });

  it("combines FTE with Spain schedule", () => {
    const result = calculateSAH({
      dailyWorkingHours: 8,
      scheduleRules: spainRules,
      fte: 0.5,
      periodStart: new Date("2026-03-09"),
      periodEnd: new Date("2026-03-13"),
      publicHolidays: [],
      absenceDays: [],
    });
    // (9*4 + 6.5*1) * 0.5 = 42.5 * 0.5 = 21.25
    expect(result.standardAvailableHours).toBe(21.25);
  });
});
