import { beforeEach, describe, expect, it, vi } from "vitest";
import { PermissionKey, SystemRole } from "@capakraken/shared";

vi.mock("@capakraken/application", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@capakraken/application")>();
  return {
    ...actual,
    approveEstimateVersion: vi.fn(),
    cloneEstimate: vi.fn(),
    commitDispoImportBatch: vi.fn(),
    countPlanningEntries: vi.fn().mockResolvedValue({ countsByRoleId: new Map() }),
    createEstimateExport: vi.fn(),
    createEstimatePlanningHandoff: vi.fn(),
    createEstimateRevision: vi.fn(),
    assessDispoImportReadiness: vi.fn(),
    loadResourceDailyAvailabilityContexts: vi.fn().mockResolvedValue(new Map()),
    getDashboardDemand: vi.fn().mockResolvedValue([]),
    getDashboardBudgetForecast: vi.fn().mockResolvedValue([]),
    getDashboardOverview: vi.fn(),
    getDashboardSkillGapSummary: vi.fn().mockResolvedValue({
      roleGaps: [],
      totalOpenPositions: 0,
      skillSupplyTop10: [],
      resourcesByRole: [],
    }),
    getDashboardProjectHealth: vi.fn().mockResolvedValue([]),
    getDashboardPeakTimes: vi.fn().mockResolvedValue([]),
    getDashboardTopValueResources: vi.fn().mockResolvedValue([]),
    getEstimateById: vi.fn(),
    listAssignmentBookings: vi.fn().mockResolvedValue([]),
    stageDispoImportBatch: vi.fn(),
    submitEstimateVersion: vi.fn(),
    updateEstimateDraft: vi.fn(),
  };
});

import { executeTool } from "../router/assistant-tools.js";
import { createToolContext } from "./assistant-tools-allocation-planning-test-helpers.js";

describe("assistant allocation create tools", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("routes allocation creation through the real allocation router path", async () => {
    const auditCreate = vi.fn().mockResolvedValue({ id: "audit_1" });
    const assignmentCreate = vi.fn().mockResolvedValue({
      id: "assignment_1",
      demandRequirementId: null,
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-06-01T00:00:00.000Z"),
      endDate: new Date("2026-06-05T00:00:00.000Z"),
      hoursPerDay: 6,
      percentage: 75,
      role: "Designer",
      roleId: null,
      dailyCostCents: 42000,
      status: "PROPOSED",
      metadata: {},
      createdAt: new Date("2026-03-29T00:00:00.000Z"),
      updatedAt: new Date("2026-03-29T00:00:00.000Z"),
      resource: {
        id: "resource_1",
        displayName: "Carol Danvers",
        eid: "EMP-001",
        lcrCents: 7000,
      },
      project: { id: "project_1", name: "Project One", shortCode: "PROJ-1" },
      roleEntity: null,
      demandRequirement: null,
    });
    const tx = {
      project: {
        findUnique: vi.fn().mockResolvedValue({ id: "project_1" }),
      },
      resource: {
        findUnique: vi.fn().mockResolvedValue({
          id: "resource_1",
          lcrCents: 7000,
          availability: {
            monday: 8,
            tuesday: 8,
            wednesday: 8,
            thursday: 8,
            friday: 8,
            saturday: 0,
            sunday: 0,
          },
        }),
      },
      assignment: {
        findMany: vi.fn().mockResolvedValue([]),
        create: assignmentCreate,
      },
      vacation: {
        findMany: vi.fn().mockResolvedValue([]),
      },
      auditLog: {
        create: auditCreate,
      },
    };
    const transaction = vi
      .fn()
      .mockImplementation(async (callback: (inner: typeof tx) => Promise<unknown>) => callback(tx));
    const ctx = createToolContext(
      {
        resource: {
          findUnique: vi.fn().mockResolvedValue({
            id: "resource_1",
            displayName: "Carol Danvers",
            eid: "EMP-001",
            lcrCents: 7000,
          }),
          findFirst: vi.fn().mockResolvedValue(null),
        },
        project: {
          findUnique: vi.fn().mockResolvedValue({
            id: "project_1",
            name: "Project One",
            shortCode: "PROJ-1",
            status: "ACTIVE",
            responsiblePerson: "Peter Parker",
            budgetCents: 0,
          }),
          findFirst: vi.fn().mockResolvedValue(null),
        },
        assignment: {
          findMany: vi.fn().mockResolvedValue([]),
          findUnique: vi.fn().mockResolvedValue(null),
        },
        $transaction: transaction,
      },
      {
        userRole: SystemRole.ADMIN,
        permissions: [PermissionKey.MANAGE_ALLOCATIONS],
      },
    );

    const result = await executeTool(
      "create_allocation",
      JSON.stringify({
        resourceId: "resource_1",
        projectId: "project_1",
        startDate: "2026-06-01",
        endDate: "2026-06-05",
        hoursPerDay: 6,
        role: "Designer",
      }),
      ctx,
    );

    expect(JSON.parse(result.content)).toEqual(
      expect.objectContaining({
        success: true,
        message:
          "Created allocation: Carol Danvers → Project One (PROJ-1), 6h/day, 2026-06-01 to 2026-06-05",
        allocationId: "assignment_1",
        status: "PROPOSED",
      }),
    );
    expect(ctx.db.resource.findUnique).toHaveBeenCalledWith({
      where: { id: "resource_1" },
      select: {
        id: true,
        displayName: true,
        eid: true,
        chapter: true,
        isActive: true,
      },
    });
    expect(ctx.db.project.findUnique).toHaveBeenCalledWith({
      where: { id: "project_1" },
      select: expect.objectContaining({
        id: true,
        shortCode: true,
        name: true,
      }),
    });
    expect(ctx.db.assignment.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: {
          resourceId: "resource_1",
          projectId: "project_1",
        },
        orderBy: { startDate: "asc" },
        include: expect.objectContaining({
          resource: {
            select: expect.objectContaining({
              id: true,
              displayName: true,
              eid: true,
              chapter: true,
              lcrCents: true,
            }),
          },
          project: {
            select: expect.objectContaining({
              id: true,
              name: true,
              shortCode: true,
              status: true,
            }),
          },
        }),
      }),
    );
    expect(assignmentCreate).toHaveBeenCalledTimes(1);
    expect(auditCreate).toHaveBeenCalledTimes(1);
  });
});
