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

describe("allocation entry update flows", () => {
  it("excludes the current assignment from conflict checks during update", async () => {
    const projectFindUnique = vi.fn().mockResolvedValue({ id: "project_1" });
    const resourceFindUnique = vi.fn().mockResolvedValue({
      id: "resource_1",
      lcrCents: 5000,
      availability: {
        monday: 8,
        tuesday: 8,
        wednesday: 8,
        thursday: 8,
        friday: 8,
        saturday: 0,
        sunday: 0,
      },
    });
    const assignmentFindMany = vi.fn().mockResolvedValue([]);
    const vacationFindMany = vi.fn().mockResolvedValue([]);
    const assignmentCreate = vi.fn().mockResolvedValue({
      id: "assignment_1",
      demandRequirementId: null,
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-03-16"),
      endDate: new Date("2026-03-27"),
      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 auditLogCreate = vi.fn().mockResolvedValue({});

    await createAssignment(
      {
        project: { findUnique: projectFindUnique },
        resource: { findUnique: resourceFindUnique },
        assignment: { findMany: assignmentFindMany, create: assignmentCreate },
        vacation: { findMany: vacationFindMany },
        auditLog: { create: auditLogCreate },
      } as never,
      {
        resourceId: "resource_1",
        projectId: "project_1",
        startDate: new Date("2026-03-16"),
        endDate: new Date("2026-03-27"),
        hoursPerDay: 4,
        percentage: 50,
        role: "Compositor",
        roleId: "role_comp",
        status: AllocationStatus.PROPOSED,
        metadata: {},
      },
    );

    expect(assignmentFindMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({
          resourceId: { in: ["resource_1"] },
          status: { not: "CANCELLED" },
        }),
      }),
    );
  });

  it("updates a linked demand requirement directly", async () => {
    const demandRequirementFindUnique = vi.fn().mockResolvedValue({
      id: "demand_1",
      projectId: "project_1",
      startDate: new Date("2026-03-16"),
      endDate: new Date("2026-03-27"),
      hoursPerDay: 4,
      percentage: 50,
      role: "FX Artist",
      roleId: "role_fx",
      headcount: 2,
      status: AllocationStatus.PROPOSED,
      project: { id: "project_1", name: "Project One", shortCode: "PRJ" },
      roleEntity: { id: "role_fx", name: "FX Artist", color: "#222222" },
    });
    const demandRequirementUpdate = vi.fn().mockResolvedValue({
      id: "demand_1",
      projectId: "project_1",
      startDate: new Date("2026-03-16"),
      endDate: new Date("2026-03-27"),
      hoursPerDay: 4,
      percentage: 50,
      role: "FX Artist",
      roleId: "role_fx",
      headcount: 1,
      status: AllocationStatus.COMPLETED,
      project: { id: "project_1", name: "Project One", shortCode: "PRJ" },
      roleEntity: { id: "role_fx", name: "FX Artist", color: "#222222" },
    });
    const auditLogCreate = vi.fn().mockResolvedValue({});

    const result = await updateDemandRequirement(
      {
        demandRequirement: {
          findUnique: demandRequirementFindUnique,
          update: demandRequirementUpdate,
        },
        auditLog: { create: auditLogCreate },
      } as never,
      "demand_1",
      {
        headcount: 1,
        status: AllocationStatus.COMPLETED,
        metadata: { source: "update-test" },
      },
    );

    expect(result.headcount).toBe(1);
    expect(auditLogCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({
          entityType: "DemandRequirement",
          entityId: "demand_1",
        }),
      }),
    );
  });

  it("updates a linked assignment directly", async () => {
    const existingAssignment = {
      id: "assignment_1",
      demandRequirementId: "demand_1",
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-03-16"),
      endDate: new Date("2026-03-27"),
      hoursPerDay: 4,
      percentage: 50,
      role: "Compositor",
      roleId: "role_comp",
      dailyCostCents: 20000,
      status: AllocationStatus.PROPOSED,
      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: {
        id: "demand_1",
        projectId: "project_1",
        startDate: new Date("2026-03-16"),
        endDate: new Date("2026-03-27"),
        hoursPerDay: 4,
        percentage: 50,
        role: "Compositor",
        roleId: "role_comp",
        headcount: 1,
        status: AllocationStatus.PROPOSED,
      },
    };
    const assignmentFindUnique = vi.fn().mockResolvedValue(existingAssignment);
    const assignmentUpdate = vi.fn().mockResolvedValue({
      ...existingAssignment,
      id: "assignment_1",
      demandRequirementId: "demand_1",
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-03-17"),
      endDate: new Date("2026-03-28"),
      hoursPerDay: 6,
      percentage: 75,
      role: "Lead Compositor",
      roleId: "role_lead_comp",
      dailyCostCents: 32000,
      status: AllocationStatus.CONFIRMED,
      metadata: { source: "update-test" },
      resource: { id: "resource_1", displayName: "Alice", eid: "E-001", lcrCents: 5000 },
      project: { id: "project_1", name: "Project One", shortCode: "PRJ" },
      roleEntity: { id: "role_lead_comp", name: "Lead Compositor", color: "#444444" },
      demandRequirement: {
        id: "demand_1",
        projectId: "project_1",
        startDate: new Date("2026-03-16"),
        endDate: new Date("2026-03-27"),
        hoursPerDay: 4,
        percentage: 50,
        role: "Compositor",
        roleId: "role_comp",
        headcount: 1,
        status: AllocationStatus.PROPOSED,
      },
    });
    const auditLogCreate = vi.fn().mockResolvedValue({});

    const result = await updateAssignment(
      {
        assignment: {
          findUnique: assignmentFindUnique,
          update: assignmentUpdate,
        },
        auditLog: { create: auditLogCreate },
      } as never,
      "assignment_1",
      {
        startDate: new Date("2026-03-17"),
        endDate: new Date("2026-03-28"),
        hoursPerDay: 6,
        percentage: 75,
        role: "Lead Compositor",
        roleId: "role_lead_comp",
        dailyCostCents: 32000,
        status: AllocationStatus.CONFIRMED,
        metadata: { source: "update-test" },
      },
    );

    expect(result.dailyCostCents).toBe(32000);
    expect(auditLogCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({
          entityType: "Assignment",
          entityId: "assignment_1",
        }),
      }),
    );
  });

});
