import { describe, it, expect } from "vitest";
import { checkDuplicateAssignment, type ExistingAssignment } from "../allocation/duplicate-check.js";

const base: ExistingAssignment = {
  id: "a1",
  resourceId: "r1",
  projectId: "p1",
  startDate: new Date("2026-03-01"),
  endDate: new Date("2026-06-30"),
  status: "CONFIRMED",
};

describe("checkDuplicateAssignment", () => {
  it("returns no duplicate when no existing assignments", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", []);
    expect(result.isDuplicate).toBe(false);
  });

  it("returns no duplicate for different project", () => {
    const result = checkDuplicateAssignment("r1", "p2", "2026-04-01", "2026-05-01", [base]);
    expect(result.isDuplicate).toBe(false);
  });

  it("returns no duplicate for different resource", () => {
    const result = checkDuplicateAssignment("r2", "p1", "2026-04-01", "2026-05-01", [base]);
    expect(result.isDuplicate).toBe(false);
  });

  it("returns no duplicate when dates don't overlap (before)", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-01-01", "2026-02-28", [base]);
    expect(result.isDuplicate).toBe(false);
  });

  it("returns no duplicate when dates don't overlap (after)", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-07-01", "2026-08-01", [base]);
    expect(result.isDuplicate).toBe(false);
  });

  it("detects duplicate with full overlap", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-03-15", "2026-05-15", [base]);
    expect(result.isDuplicate).toBe(true);
    expect(result.conflictingAssignment?.id).toBe("a1");
    expect(result.message).toContain("already assigned");
  });

  it("detects duplicate with partial overlap (start before, end during)", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-02-15", "2026-04-01", [base]);
    expect(result.isDuplicate).toBe(true);
  });

  it("detects duplicate with partial overlap (start during, end after)", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-05-01", "2026-07-15", [base]);
    expect(result.isDuplicate).toBe(true);
  });

  it("detects duplicate on exact same dates", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-03-01", "2026-06-30", [base]);
    expect(result.isDuplicate).toBe(true);
  });

  it("ignores CANCELLED assignments", () => {
    const cancelled = { ...base, status: "CANCELLED" };
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", [cancelled]);
    expect(result.isDuplicate).toBe(false);
  });

  it("ignores DRAFT assignments", () => {
    const draft = { ...base, status: "DRAFT" };
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", [draft]);
    expect(result.isDuplicate).toBe(false);
  });

  it("excludes self by ID (for updates)", () => {
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", [base], "a1");
    expect(result.isDuplicate).toBe(false);
  });

  it("does not exclude other assignments when excludeId is set", () => {
    const other: ExistingAssignment = { ...base, id: "a2" };
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", [other], "a1");
    expect(result.isDuplicate).toBe(true);
  });

  it("works with string dates", () => {
    const strAssignment: ExistingAssignment = {
      ...base,
      startDate: "2026-03-01",
      endDate: "2026-06-30",
    };
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", [strAssignment]);
    expect(result.isDuplicate).toBe(true);
  });

  it("checks PROPOSED status as active", () => {
    const proposed = { ...base, status: "PROPOSED" };
    const result = checkDuplicateAssignment("r1", "p1", "2026-04-01", "2026-05-01", [proposed]);
    expect(result.isDuplicate).toBe(true);
  });

  it("formats conflict dates from local-midnight Date objects without shifting the calendar day", () => {
    const localDateAssignment: ExistingAssignment = {
      ...base,
      startDate: new Date(2026, 3, 6),
      endDate: new Date(2026, 3, 17),
    };

    const result = checkDuplicateAssignment(
      "r1",
      "p1",
      new Date(2026, 3, 9),
      new Date(2026, 3, 10),
      [localDateAssignment],
    );

    expect(result.isDuplicate).toBe(true);
    expect(result.message).toContain("2026-04-06");
    expect(result.message).toContain("2026-04-17");
  });
});
