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

import {
  createToolContext,
  executeTool,
  getDashboardChargeabilityOverview,
  getDashboardDemand,
  getDashboardOverview,
  getDashboardPeakTimes,
  getDashboardProjectHealth,
  getDashboardSkillGapSummary,
  getDashboardTopValueResources,
} from "./assistant-tools-dashboard-test-helpers.js";

describe("assistant dashboard tools detail aggregation", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("routes dashboard detail reads through dashboard router callers", async () => {
    vi.mocked(getDashboardOverview).mockResolvedValue({
      totalResources: 12,
      activeResources: 10,
      inactiveResources: 2,
      totalProjects: 4,
      activeProjects: 3,
      inactiveProjects: 1,
      totalAllocations: 8,
      activeAllocations: 7,
      cancelledAllocations: 1,
      approvedVacations: 2,
      totalEstimates: 5,
      budgetSummary: {
        totalBudgetCents: 500_000,
        totalCostCents: 240_000,
        avgUtilizationPercent: 48,
      },
      budgetBasis: {
        remainingBudgetCents: 260_000,
        budgetedProjects: 3,
        unbudgetedProjects: 1,
        trackedAssignmentCount: 8,
        windowStart: new Date("2026-01-01T00:00:00.000Z"),
        windowEnd: new Date("2026-06-30T00:00:00.000Z"),
      },
      recentActivity: [],
      projectsByStatus: [],
      chapterUtilization: [
        {
          chapter: "Delivery",
          resourceCount: 4,
          avgChargeabilityTarget: 78,
        },
      ],
    });
    vi.mocked(getDashboardPeakTimes).mockResolvedValue([
      {
        period: "2026-03",
        groups: [],
        totalHours: 320.4,
        capacityHours: 400.2,
        utilizationPct: 80,
        derivation: {
          periodStart: "2026-03-01",
          periodEnd: "2026-03-31",
          calendarContextCount: 1,
          resourceCount: 4,
          groupCount: 1,
          baseAvailableHours: 416.2,
          calendarLocations: [
            {
              countryCode: "DE",
              countryName: "Germany",
              federalState: "BY",
              metroCityName: "Augsburg",
              resourceCount: 4,
              effectiveAvailableHours: 400.2,
            },
          ],
          bookedHours: 320.4,
          capacityHours: 400.2,
          remainingCapacityHours: 79.8,
          overbookedHours: 0,
          utilizationPct: 80,
          effectiveAvailableHours: 400.2,
          publicHolidayHoursDeduction: 16,
          absenceDayEquivalent: 1.5,
          absenceHoursDeduction: 12.5,
        },
      },
    ]);
    vi.mocked(getDashboardTopValueResources).mockResolvedValue([
      {
        id: "res_1",
        eid: "pparker",
        displayName: "Peter Parker",
        chapter: "Delivery",
        valueScore: 91,
        valueScoreBreakdown: {
          skillDepth: 85,
          skillBreadth: 74,
          costEfficiency: 93,
          chargeability: 78,
          experience: 88,
          total: 91,
        },
        valueScoreUpdatedAt: new Date("2026-03-03T00:00:00.000Z"),
        lcrCents: 9_500,
        countryCode: "DE",
        countryName: "Germany",
        federalState: "BY",
        metroCityName: "Augsburg",
      },
    ]);
    vi.mocked(getDashboardDemand).mockResolvedValue([
      {
        id: "project_1",
        name: "Gelddruckmaschine",
        shortCode: "GDM",
        allocatedHours: 120,
        requiredFTEs: 4,
        resourceCount: 2,
        derivation: {
          periodStart: "2026-01-01",
          periodEnd: "2026-06-30",
          periodWorkingHoursBase: 1040,
          requiredHours: 2080,
          requiredFTEs: 4,
          fillPct: 50,
          demandSource: "DEMAND_REQUIREMENTS",
          calendarLocations: [
            {
              countryCode: "DE",
              countryName: "Germany",
              federalState: "BY",
              metroCityName: "Augsburg",
              resourceCount: 2,
              allocatedHours: 120,
            },
          ],
        },
      },
    ]);
    vi.mocked(getDashboardChargeabilityOverview).mockResolvedValue({
      rows: [
        {
          id: "res_1",
          eid: "pparker",
          displayName: "Peter Parker",
          chapter: "Delivery",
          chargeabilityTarget: 78,
          actualChargeability: 70,
          expectedChargeability: 76,
          derivation: {
            weeklyAvailabilityHours: 40,
            baseWorkingDays: 22,
            effectiveWorkingDayEquivalent: 21,
            baseAvailableHours: 176,
            effectiveAvailableHours: 168,
            publicHolidayCount: 1,
            publicHolidayWorkdayCount: 1,
            publicHolidayHoursDeduction: 8,
            absenceDayEquivalent: 0,
            absenceHoursDeduction: 0,
            actualBookedHours: 117.6,
            expectedBookedHours: 127.7,
            targetBookedHours: 131,
            unassignedHours: 40.3,
          },
        },
      ],
      top: [],
      watchlist: [],
      month: "2026-03",
    });
    vi.mocked(getDashboardProjectHealth).mockResolvedValue([
      {
        id: "project_1",
        projectName: "Gelddruckmaschine",
        shortCode: "GDM",
        status: "ACTIVE",
        clientId: "client_1",
        clientName: "Acme",
        budgetHealth: 58,
        staffingHealth: 46,
        timelineHealth: 61,
        compositeScore: 55,
        budgetUtilizationPercent: 73,
        remainingBudgetCents: 88_000,
        demandHeadcountTotal: 4,
        demandHeadcountFilled: 2,
        demandHeadcountOpen: 2,
        demandRequirementCount: 2,
        plannedEndDate: new Date("2026-09-30T00:00:00.000Z"),
        daysUntilEndDate: 183,
        timelineStatus: "DUE_SOON",
        derivation: {
          periodStart: "2026-01-01",
          periodEnd: "2026-06-30",
          calendarContextCount: 1,
          holidayAwareAssignmentCount: 2,
          fallbackAssignmentCount: 0,
          baseSpentCents: 140_000,
          adjustedSpentCents: 132_000,
          publicHolidayDayEquivalent: 1,
          publicHolidayCostDeductionCents: 5_000,
          absenceDayEquivalent: 0.5,
          absenceCostDeductionCents: 3_000,
        },
      },
    ]);
    vi.mocked(getDashboardSkillGapSummary).mockResolvedValue({
      roleGaps: [
        { role: "Pipeline TD", needed: 4, filled: 1, gap: 3, fillRate: 25 },
        { role: "Lighting TD", needed: 2, filled: 1, gap: 1, fillRate: 50 },
      ],
      totalOpenPositions: 4,
      skillSupplyTop10: [
        { skill: "houdini", resourceCount: 5 },
        { skill: "nuke", resourceCount: 4 },
      ],
      resourcesByRole: [
        { role: "Compositor", count: 6 },
        { role: "Pipeline TD", count: 2 },
      ],
    });

    const ctx = createToolContext(
      {
        systemSettings: {
          findUnique: vi.fn().mockResolvedValue(null),
        },
      },
      { userRole: SystemRole.CONTROLLER },
    );

    const result = await executeTool("get_dashboard_detail", JSON.stringify({ section: "all" }), ctx);

    expect(getDashboardOverview).toHaveBeenCalledTimes(1);
    expect(getDashboardPeakTimes).toHaveBeenCalledWith(
      ctx.db,
      expect.objectContaining({
        startDate: new Date("2026-01-01T00:00:00.000Z"),
        endDate: new Date("2026-06-30T00:00:00.000Z"),
        granularity: "month",
        groupBy: "project",
      }),
    );
    expect(getDashboardTopValueResources).toHaveBeenCalledWith(
      ctx.db,
      expect.objectContaining({
        limit: 10,
        userRole: SystemRole.CONTROLLER,
      }),
    );
    expect(getDashboardDemand).toHaveBeenCalledWith(
      ctx.db,
      expect.objectContaining({
        startDate: new Date("2026-01-01T00:00:00.000Z"),
        endDate: new Date("2026-06-30T00:00:00.000Z"),
        groupBy: "project",
      }),
    );
    expect(JSON.parse(result.content)).toEqual({
      peakTimes: [
        {
          month: "2026-03",
          totalHours: 320.4,
          totalHoursPerDay: 320.4,
          capacityHours: 400.2,
          utilizationPct: 80,
          calendarContextCount: 1,
          calendarLocations: [
            {
              countryCode: "DE",
              countryName: "Germany",
              federalState: "BY",
              metroCityName: "Augsburg",
              resourceCount: 4,
              effectiveAvailableHours: 400.2,
            },
          ],
          explainability: {
            periodStart: "2026-03-01",
            periodEnd: "2026-03-31",
            resourceCount: 4,
            groupCount: 1,
            baseAvailableHours: 416.2,
            effectiveAvailableHours: 400.2,
            publicHolidayHoursDeduction: 16,
            absenceDayEquivalent: 1.5,
            absenceHoursDeduction: 12.5,
            remainingCapacityHours: 79.8,
            overbookedHours: 0,
          },
        },
      ],
      topResources: [
        {
          name: "Peter Parker",
          eid: "pparker",
          chapter: "Delivery",
          lcr: "95,00 EUR",
          valueScore: 91,
          valueScoreBreakdown: {
            skillDepth: 85,
            skillBreadth: 74,
            costEfficiency: 93,
            chargeability: 78,
            experience: 88,
            total: 91,
          },
          valueScoreUpdatedAt: "2026-03-03T00:00:00.000Z",
          countryCode: "DE",
          countryName: "Germany",
          federalState: "BY",
          metroCityName: "Augsburg",
        },
      ],
      demandPipeline: [
        {
          project: "Gelddruckmaschine (GDM)",
          needed: 2,
          requiredFTEs: 4,
          allocatedResources: 2,
          allocatedHours: 120,
          calendarLocations: [
            {
              countryCode: "DE",
              countryName: "Germany",
              federalState: "BY",
              metroCityName: "Augsburg",
              resourceCount: 2,
              allocatedHours: 120,
            },
          ],
          explainability: {
            periodStart: "2026-01-01",
            periodEnd: "2026-06-30",
            periodWorkingHoursBase: 1040,
            requiredHours: 2080,
            fillPct: 50,
            demandSource: "DEMAND_REQUIREMENTS",
            calendarContextCount: 1,
          },
        },
      ],
      chargeabilityByChapter: [
        {
          chapter: "Delivery",
          headcount: 1,
          avgTargetPct: 78,
          avgActualPct: 70,
          avgExpectedPct: 76,
          gapToTargetPct: 8,
          avgTarget: "78%",
          avgActual: "70%",
          avgExpected: "76%",
          explainability: {
            month: "2026-03",
            resourceCount: 1,
            derivedHeadcount: 1,
            baseAvailableHours: 176,
            effectiveAvailableHours: 168,
            actualBookedHours: 117.6,
            expectedBookedHours: 127.7,
            targetBookedHours: 131,
            publicHolidayHoursDeduction: 8,
            absenceDayEquivalent: 0,
            absenceHoursDeduction: 0,
            unassignedHours: 40.3,
          },
        },
      ],
      projectHealth: [
        {
          project: "Gelddruckmaschine (GDM)",
          status: "ACTIVE",
          overall: 55,
          rating: "at_risk",
          budget: 58,
          staffing: 46,
          timeline: 61,
          timelineStatus: "DUE_SOON",
          daysUntilEndDate: 183,
          demandHeadcountOpen: 2,
          explainability: {
            demandHeadcountTotal: 4,
            demandHeadcountFilled: 2,
            demandHeadcountOpen: 2,
            demandRequirementCount: 2,
            plannedEndDate: "2026-09-30T00:00:00.000Z",
            budgetUtilizationPercent: 73,
            remainingBudgetCents: 88_000,
            calendarContextCount: 1,
            holidayAwareAssignmentCount: 2,
            publicHolidayCostDeductionCents: 5_000,
            absenceCostDeductionCents: 3_000,
          },
        },
      ],
      skillGaps: {
        totalOpenPositions: 4,
        roleGaps: [
          { role: "Pipeline TD", gap: 3, needed: 4, filled: 1, fillRate: 25 },
          { role: "Lighting TD", gap: 1, needed: 2, filled: 1, fillRate: 50 },
        ],
        topSkillsInSupply: [
          { skill: "houdini", resourceCount: 5 },
          { skill: "nuke", resourceCount: 4 },
        ],
        resourcesByRole: [
          { role: "Compositor", count: 6 },
          { role: "Pipeline TD", count: 2 },
        ],
      },
    });
  });

  it("routes the isolated skill gap detail section without unrelated dashboard reads", async () => {
    vi.mocked(getDashboardSkillGapSummary).mockResolvedValue({
      roleGaps: [
        { role: "Pipeline TD", needed: 4, filled: 1, gap: 3, fillRate: 25 },
      ],
      totalOpenPositions: 3,
      skillSupplyTop10: [{ skill: "houdini", resourceCount: 5 }],
      resourcesByRole: [{ role: "Pipeline TD", count: 2 }],
    });

    const ctx = createToolContext(
      {
        systemSettings: {
          findUnique: vi.fn().mockResolvedValue(null),
        },
      },
      { userRole: SystemRole.CONTROLLER },
    );

    const result = await executeTool(
      "get_dashboard_detail",
      JSON.stringify({ section: "skill_gaps" }),
      ctx,
    );

    expect(JSON.parse(result.content)).toEqual({
      skillGaps: {
        totalOpenPositions: 3,
        roleGaps: [
          { role: "Pipeline TD", gap: 3, needed: 4, filled: 1, fillRate: 25 },
        ],
        topSkillsInSupply: [{ skill: "houdini", resourceCount: 5 }],
        resourcesByRole: [{ role: "Pipeline TD", count: 2 }],
      },
    });
    expect(getDashboardSkillGapSummary).toHaveBeenCalledTimes(1);
    expect(getDashboardOverview).not.toHaveBeenCalled();
    expect(getDashboardPeakTimes).not.toHaveBeenCalled();
    expect(getDashboardDemand).not.toHaveBeenCalled();
    expect(getDashboardProjectHealth).not.toHaveBeenCalled();
    expect(getDashboardChargeabilityOverview).not.toHaveBeenCalled();
    expect(getDashboardTopValueResources).not.toHaveBeenCalled();
  });
});
