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 { executeTool } from "../router/assistant-tools.js";

import { createToolContext } from "./assistant-tools-advanced-timeline-test-helpers.js";

describe("assistant timeline resource selection tools", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("finds the best project resource with holiday-aware remaining capacity and LCR ranking", async () => {
    const assignmentFindMany = vi
      .fn()
      .mockResolvedValueOnce([
        {
          resourceId: "res_carol",
          hoursPerDay: 2,
          startDate: new Date("2026-01-05T00:00:00.000Z"),
          endDate: new Date("2026-01-16T00:00:00.000Z"),
          status: "PROPOSED",
          resource: {
            id: "res_carol",
            eid: "carol.danvers",
            displayName: "Carol Danvers",
            chapter: "Delivery",
            lcrCents: 7664,
            availability: { monday: 8, tuesday: 8, wednesday: 8, thursday: 8, friday: 8 },
            countryId: "country_de",
            federalState: "HH",
            metroCityId: "city_hamburg",
            country: { code: "DE", name: "Deutschland" },
            metroCity: { name: "Hamburg" },
            areaRole: { name: "Artist" },
          },
        },
        {
          resourceId: "res_steve",
          hoursPerDay: 4,
          startDate: new Date("2026-01-05T00:00:00.000Z"),
          endDate: new Date("2026-01-16T00:00:00.000Z"),
          status: "CONFIRMED",
          resource: {
            id: "res_steve",
            eid: "steve.rogers",
            displayName: "Steve Rogers",
            chapter: "Delivery",
            lcrCents: 13377,
            availability: { monday: 8, tuesday: 8, wednesday: 8, thursday: 8, friday: 8 },
            countryId: "country_de",
            federalState: "BY",
            metroCityId: "city_augsburg",
            country: { code: "DE", name: "Deutschland" },
            metroCity: { name: "Augsburg" },
            areaRole: { name: "Artist" },
          },
        },
      ])
      .mockResolvedValueOnce([
        {
          resourceId: "res_carol",
          projectId: "project_lari",
          hoursPerDay: 2,
          startDate: new Date("2026-01-05T00:00:00.000Z"),
          endDate: new Date("2026-01-16T00:00:00.000Z"),
          status: "PROPOSED",
          project: { name: "Gelddruckmaschine", shortCode: "LARI" },
        },
        {
          resourceId: "res_steve",
          projectId: "project_lari",
          hoursPerDay: 4,
          startDate: new Date("2026-01-05T00:00:00.000Z"),
          endDate: new Date("2026-01-16T00:00:00.000Z"),
          status: "CONFIRMED",
          project: { name: "Gelddruckmaschine", shortCode: "LARI" },
        },
      ]);

    const ctx = createToolContext(
      {
        project: {
          findUnique: vi
            .fn()
            .mockResolvedValueOnce(null)
            .mockResolvedValueOnce({
              id: "project_lari",
              name: "Gelddruckmaschine",
              shortCode: "LARI",
              status: "ACTIVE",
              responsiblePerson: "Larissa Joos",
              startDate: new Date("2026-01-05T00:00:00.000Z"),
              endDate: new Date("2026-01-16T00:00:00.000Z"),
            })
            .mockResolvedValueOnce({
              id: "project_lari",
              name: "Gelddruckmaschine",
              shortCode: "LARI",
              status: "ACTIVE",
              responsiblePerson: "Larissa Joos",
            }),
          findFirst: vi.fn(),
        },
        assignment: {
          findMany: assignmentFindMany,
        },
        vacation: {
          findMany: vi.fn().mockResolvedValue([]),
        },
      },
      [
        PermissionKey.VIEW_COSTS,
        PermissionKey.VIEW_PLANNING,
        PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
      ],
    );

    const result = await executeTool(
      "find_best_project_resource",
      JSON.stringify({
        projectIdentifier: "LARI",
        startDate: "2026-01-05",
        endDate: "2026-01-16",
        minHoursPerDay: 3,
        rankingMode: "lowest_lcr",
      }),
      ctx,
    );

    const parsed = JSON.parse(result.content) as {
      project: { shortCode: string };
      candidateCount: number;
      bestMatch: {
        name: string;
        remainingHoursPerDay: number;
        lcrCents: number | null;
        federalState: string | null;
        metroCity: string | null;
        baseAvailableHours: number;
        holidaySummary: { count: number };
      };
      candidates: Array<{
        name: string;
        remainingHoursPerDay: number;
        workingDays: number;
        baseAvailableHours: number;
        holidaySummary: { count: number; hoursDeduction: number };
        capacityBreakdown: { holidayHoursDeduction: number };
      }>;
    };

    expect(parsed.project.shortCode).toBe("LARI");
    expect(parsed.candidateCount).toBe(2);
    expect(parsed.bestMatch).toEqual(
      expect.objectContaining({
        name: "Carol Danvers",
        remainingHoursPerDay: 6,
        lcrCents: 7664,
        federalState: "HH",
        metroCity: "Hamburg",
        baseAvailableHours: 80,
        holidaySummary: expect.objectContaining({ count: 0 }),
      }),
    );
    expect(parsed.candidates).toEqual([
      expect.objectContaining({
        name: "Carol Danvers",
        remainingHoursPerDay: 6,
        workingDays: 10,
        baseAvailableHours: 80,
        holidaySummary: expect.objectContaining({ count: 0, hoursDeduction: 0 }),
        capacityBreakdown: expect.objectContaining({ holidayHoursDeduction: 0 }),
      }),
      expect.objectContaining({
        name: "Steve Rogers",
        remainingHoursPerDay: 4,
        workingDays: 9,
        baseAvailableHours: 80,
        holidaySummary: expect.objectContaining({ count: 1, hoursDeduction: 8 }),
        capacityBreakdown: expect.objectContaining({ holidayHoursDeduction: 8 }),
      }),
    ]);
  });
});
