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 demand fill tool", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("routes demand filling through the real allocation router path", async () => {
    const auditCreate = vi.fn().mockResolvedValue({ id: "audit_1" });
    const assignmentCreate = vi.fn().mockResolvedValue({
      id: "assignment_1",
      demandRequirementId: "demand_1",
      resourceId: "resource_1",
      projectId: "project_1",
      startDate: new Date("2026-05-01T00:00:00.000Z"),
      endDate: new Date("2026-05-15T00:00:00.000Z"),
      hoursPerDay: 6,
      percentage: 75,
      role: "Designer",
      roleId: "role_1",
      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: { id: "role_1", name: "Designer", color: "#00AAFF" },
      demandRequirement: {
        id: "demand_1",
        projectId: "project_1",
        startDate: new Date("2026-05-01T00:00:00.000Z"),
        endDate: new Date("2026-05-15T00:00:00.000Z"),
        hoursPerDay: 6,
        percentage: 75,
        role: "Designer",
        roleId: "role_1",
        headcount: 1,
        status: "PROPOSED",
      },
    });
    const txDemandUpdate = vi.fn().mockResolvedValue({
      id: "demand_1",
      projectId: "project_1",
      headcount: 1,
      status: "COMPLETED",
    });
    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,
          },
        }),
      },
      demandRequirement: {
        findUnique: vi.fn().mockResolvedValue({
          id: "demand_1",
          projectId: "project_1",
        }),
        update: txDemandUpdate,
      },
      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 demandRecord = {
      id: "demand_1",
      projectId: "project_1",
      startDate: new Date("2026-05-01T00:00:00.000Z"),
      endDate: new Date("2026-05-15T00:00:00.000Z"),
      hoursPerDay: 6,
      percentage: 75,
      role: "Designer",
      roleId: "role_1",
      headcount: 1,
      status: "PROPOSED",
      metadata: {},
      roleEntity: { name: "Designer" },
      project: { id: "project_1", name: "Project One", shortCode: "PROJ-1" },
    };
    const demandFindUnique = vi.fn()
      .mockResolvedValueOnce(demandRecord)
      .mockResolvedValueOnce(demandRecord);
    const resourceFindUnique = vi.fn().mockResolvedValue({
      id: "resource_1",
      displayName: "Carol Danvers",
      lcrCents: 7000,
      availability: {
        monday: 8,
        tuesday: 8,
        wednesday: 8,
        thursday: 8,
        friday: 8,
        saturday: 0,
        sunday: 0,
      },
    });
    const ctx = createToolContext(
      {
        demandRequirement: {
          findUnique: demandFindUnique,
        },
        project: {
          findUnique: vi.fn().mockResolvedValue({
            id: "project_1",
            name: "Project One",
            shortCode: "PROJ-1",
            budgetCents: 100000,
          }),
        },
        user: {
          findMany: vi.fn().mockResolvedValue([]),
        },
        notification: {
          findFirst: vi.fn().mockResolvedValue(null),
          create: vi.fn(),
        },
        resource: {
          findUnique: resourceFindUnique,
          findFirst: vi.fn().mockResolvedValue(null),
        },
        assignment: {
          findMany: vi.fn().mockResolvedValue([]),
        },
        $transaction: transaction,
      },
      {
        userRole: SystemRole.ADMIN,
        permissions: [PermissionKey.MANAGE_ALLOCATIONS],
      },
    );

    const result = await executeTool(
      "fill_demand",
      JSON.stringify({ demandId: "demand_1", resourceId: "resource_1" }),
      ctx,
    );

    expect(JSON.parse(result.content)).toEqual(expect.objectContaining({
      success: true,
      message: "Assigned Carol Danvers to Designer on Project One (PROJ-1)",
      assignmentId: "assignment_1",
    }));
    expect(assignmentCreate).toHaveBeenCalledTimes(1);
    expect(txDemandUpdate).toHaveBeenCalledWith(expect.objectContaining({
      where: { id: "demand_1" },
      data: { status: "COMPLETED" },
    }));
    expect(auditCreate).toHaveBeenCalledTimes(1);
  });
});
