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

vi.mock("@capakraken/application", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@capakraken/application")>();
  return {
    ...actual,
    getDashboardBudgetForecast: vi.fn().mockResolvedValue([]),
    getDashboardPeakTimes: vi.fn().mockResolvedValue([]),
    listAssignmentBookings: vi.fn().mockResolvedValue([]),
  };
});

vi.mock("../sse/event-bus.js", () => ({
  emitAllocationCreated: vi.fn(),
  emitAllocationDeleted: vi.fn(),
  emitAllocationUpdated: vi.fn(),
  emitProjectShifted: vi.fn(),
}));

vi.mock("../lib/budget-alerts.js", () => ({
  checkBudgetThresholds: vi.fn(),
}));

vi.mock("../lib/cache.js", () => ({
  invalidateDashboardCache: vi.fn(),
}));

import { listAssignmentBookings } from "@capakraken/application";
import { executeTool } from "../router/assistant-tools.js";
import { createToolContext } from "./assistant-tools-advanced-timeline-test-helpers.js";

describe("assistant advanced project timeline context tool", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(listAssignmentBookings).mockResolvedValue([]);
  });

  it("returns project timeline context with cross-project overlap summaries", async () => {
    const project = {
      id: "project_ctx",
      name: "Gelddruckmaschine",
      shortCode: "GDM",
      orderType: "CHARGEABLE",
      budgetCents: 100000,
      winProbability: 100,
      status: "ACTIVE",
      startDate: new Date("2026-01-05T00:00:00.000Z"),
      endDate: new Date("2026-01-16T00:00:00.000Z"),
      staffingReqs: null,
    };

    vi.mocked(listAssignmentBookings).mockResolvedValue([
      {
        id: "asg_project",
        projectId: "project_ctx",
        resourceId: "res_1",
        startDate: new Date("2026-01-05T00:00:00.000Z"),
        endDate: new Date("2026-01-16T00:00:00.000Z"),
        hoursPerDay: 6,
        dailyCostCents: 0,
        status: "CONFIRMED",
        project: { id: "project_ctx", name: "Gelddruckmaschine", shortCode: "GDM", status: "ACTIVE", orderType: "CHARGEABLE", dynamicFields: null },
        resource: { id: "res_1", displayName: "Alice", chapter: "Delivery" },
      },
      {
        id: "asg_other",
        projectId: "project_other",
        resourceId: "res_1",
        startDate: new Date("2026-01-08T00:00:00.000Z"),
        endDate: new Date("2026-01-10T00:00:00.000Z"),
        hoursPerDay: 4,
        dailyCostCents: 0,
        status: "CONFIRMED",
        project: { id: "project_other", name: "Other Project", shortCode: "OTH", status: "ACTIVE", orderType: "CHARGEABLE", dynamicFields: null },
        resource: { id: "res_1", displayName: "Alice", chapter: "Delivery" },
      },
    ]);

    const ctx = createToolContext(
      {
        project: {
          findUnique: vi
            .fn()
            .mockResolvedValueOnce(project)
            .mockResolvedValueOnce(project),
        },
        demandRequirement: {
          findMany: vi.fn().mockResolvedValue([
            {
              id: "dem_ctx",
              projectId: "project_ctx",
              resourceId: null,
              role: "Artist",
              hoursPerDay: 6,
              startDate: new Date("2026-01-05T00:00:00.000Z"),
              endDate: new Date("2026-01-16T00:00:00.000Z"),
              status: "OPEN",
              metadata: null,
              project,
              roleEntity: null,
            },
          ]),
        },
        assignment: {
          findMany: vi.fn().mockResolvedValue([
            {
              id: "asg_project",
              projectId: "project_ctx",
              resourceId: "res_1",
              role: "Artist",
              hoursPerDay: 6,
              startDate: new Date("2026-01-05T00:00:00.000Z"),
              endDate: new Date("2026-01-16T00:00:00.000Z"),
              status: "CONFIRMED",
              metadata: null,
              resource: {
                id: "res_1",
                displayName: "Alice",
                eid: "EMP-1",
                chapter: "Delivery",
                lcrCents: 10000,
                availability: { monday: 8, tuesday: 8, wednesday: 8, thursday: 8, friday: 8 },
              },
              project,
              roleEntity: null,
            },
          ]),
        },
        resource: {
          findMany: vi.fn().mockResolvedValue([
            {
              id: "res_1",
              countryId: "country_de",
              federalState: "BY",
              metroCityId: "city_munich",
              country: { code: "DE" },
              metroCity: { name: "Muenchen" },
            },
          ]),
        },
      },
      [PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS],
    );

    const result = await executeTool(
      "get_project_timeline_context",
      JSON.stringify({
        projectIdentifier: "project_ctx",
      }),
      ctx,
    );

    const parsed = JSON.parse(result.content) as {
      project: { id: string; shortCode: string };
      summary: {
        demandCount: number;
        assignmentCount: number;
        conflictedAssignmentCount: number;
        overlayCount: number;
      };
      assignmentConflicts: Array<{
        assignmentId: string;
        crossProjectOverlapCount: number;
        overlaps: Array<{ projectShortCode: string; sameProject: boolean }>;
      }>;
      holidayOverlays: Array<{ startDate: string }>;
    };

    expect(parsed.project).toEqual(
      expect.objectContaining({
        id: "project_ctx",
        shortCode: "GDM",
      }),
    );
    expect(parsed.summary).toEqual(
      expect.objectContaining({
        demandCount: 1,
        assignmentCount: 1,
        conflictedAssignmentCount: 1,
        overlayCount: 1,
      }),
    );
    expect(parsed.assignmentConflicts).toEqual([
      expect.objectContaining({
        assignmentId: "asg_project",
        crossProjectOverlapCount: 1,
        overlaps: expect.arrayContaining([
          expect.objectContaining({
            projectShortCode: "OTH",
            sameProject: false,
          }),
        ]),
      }),
    ]);
    expect(parsed.holidayOverlays).toEqual([
      expect.objectContaining({
        startDate: "2026-01-06",
      }),
    ]);
  });
});
