import { AllocationStatus } from "@capakraken/shared";
import { describe, expect, it, vi } from "vitest";
import { updateAllocationEntry } from "../index.js";

describe("allocation entry resolution helpers", () => {
  it("updates an explicit demand requirement", async () => {
    const existingDemand = {
      id: "demand_1",
      projectId: "project_1",
      startDate: new Date("2026-03-16"),
      endDate: new Date("2026-03-20"),
      hoursPerDay: 4,
      percentage: 50,
      role: "FX Artist",
      roleId: "role_fx",
      headcount: 1,
      status: AllocationStatus.PROPOSED,
      metadata: {},
      createdAt: new Date("2026-03-13"),
      updatedAt: new Date("2026-03-13"),
      project: { id: "project_1", name: "Project One", shortCode: "PRJ" },
      roleEntity: { id: "role_fx", name: "FX Artist", color: "#222222" },
    };
    const updatedDemand = {
      ...existingDemand,
      headcount: 2,
      status: AllocationStatus.CONFIRMED,
      metadata: { source: "entry-test" },
      updatedAt: new Date("2026-03-14"),
    };

    const demandRequirementFindUnique = vi.fn().mockResolvedValue(existingDemand);
    const demandRequirementUpdate = vi.fn().mockResolvedValue(updatedDemand);
    const assignmentFindUnique = vi.fn().mockResolvedValue(null);
    const assignmentUpdate = vi.fn();
    const auditLogCreate = vi.fn().mockResolvedValue({});

    const result = await updateAllocationEntry(
      {
        demandRequirement: {
          findUnique: demandRequirementFindUnique,
          update: demandRequirementUpdate,
        },
        assignment: {
          findUnique: assignmentFindUnique,
          update: assignmentUpdate,
        },
        auditLog: { create: auditLogCreate },
      } as never,
      {
        id: "demand_1",
        demandRequirementUpdate: {
          headcount: 2,
          status: AllocationStatus.CONFIRMED,
          metadata: { source: "entry-test" },
        },
        assignmentUpdate: {},
      },
    );

    expect(result.strategy).toBe("explicit_demand");
    expect(result.allocation.id).toBe("demand_1");
    expect(result.allocation.isPlaceholder).toBe(true);
    expect(result.allocation.headcount).toBe(2);
    expect(demandRequirementUpdate).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { id: "demand_1" },
        data: expect.objectContaining({
          headcount: 2,
          status: AllocationStatus.CONFIRMED,
        }),
      }),
    );
    expect(assignmentUpdate).not.toHaveBeenCalled();
  });

  it("updates an explicit assignment", async () => {
    const existingAssignment = {
      id: "assignment_1",
      demandRequirementId: null,
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-03-16"),
      endDate: new Date("2026-03-20"),
      hoursPerDay: 4,
      percentage: 50,
      role: "Compositor",
      roleId: "role_comp",
      dailyCostCents: 20000,
      status: AllocationStatus.PROPOSED,
      metadata: {},
      createdAt: new Date("2026-03-13"),
      updatedAt: new Date("2026-03-13"),
      resource: {
        id: "resource_1",
        displayName: "Alice",
        eid: "E-001",
        lcrCents: 5000,
      },
      project: { id: "project_1", name: "Project One", shortCode: "PRJ" },
      roleEntity: { id: "role_comp", name: "Compositor", color: "#111111" },
      demandRequirement: null,
    };
    const updatedAssignment = {
      ...existingAssignment,
      hoursPerDay: 6,
      percentage: 75,
      dailyCostCents: 30000,
      status: AllocationStatus.ACTIVE,
      updatedAt: new Date("2026-03-14"),
    };

    const demandRequirementFindUnique = vi.fn().mockResolvedValue(null);
    const assignmentFindUnique = vi.fn().mockResolvedValue(existingAssignment);
    const assignmentUpdate = vi.fn().mockResolvedValue(updatedAssignment);
    const auditLogCreate = vi.fn().mockResolvedValue({});

    const result = await updateAllocationEntry(
      {
        demandRequirement: {
          findUnique: demandRequirementFindUnique,
        },
        assignment: {
          findUnique: assignmentFindUnique,
          update: assignmentUpdate,
        },
        auditLog: { create: auditLogCreate },
      } as never,
      {
        id: "assignment_1",
        demandRequirementUpdate: {},
        assignmentUpdate: {
          hoursPerDay: 6,
          percentage: 75,
          dailyCostCents: 30000,
          status: AllocationStatus.ACTIVE,
        },
      },
    );

    expect(result.strategy).toBe("explicit_assignment");
    expect(result.allocation.id).toBe("assignment_1");
    expect(assignmentUpdate).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { id: "assignment_1" },
      }),
    );
  });

  it("throws NOT_FOUND when the id does not match any demand or assignment", async () => {
    const demandRequirementFindUnique = vi.fn().mockResolvedValue(null);
    const assignmentFindUnique = vi.fn().mockResolvedValue(null);

    await expect(
      updateAllocationEntry(
        {
          demandRequirement: {
            findUnique: demandRequirementFindUnique,
          },
          assignment: {
            findUnique: assignmentFindUnique,
          },
        } as never,
        {
          id: "nonexistent_id",
          demandRequirementUpdate: {
            status: AllocationStatus.CONFIRMED,
          },
          assignmentUpdate: {},
        },
      ),
    ).rejects.toMatchObject({
      code: "NOT_FOUND",
      message: "Allocation not found",
    });
  });

});
