import { TRPCError } from "@trpc/server";
import { beforeEach, describe, expect, it, vi } from "vitest";

vi.mock("../router/timeline-holiday-read.js", async () => {
  const actual = await vi.importActual<typeof import("../router/timeline-holiday-read.js")>(
    "../router/timeline-holiday-read.js",
  );

  return {
    ...actual,
    loadTimelineHolidayOverlays: vi.fn(),
    formatHolidayOverlays: vi.fn(actual.formatHolidayOverlays),
  };
});

import {
  loadTimelineProjectContextDetailArtifacts,
  resolveTimelineProjectContextPeriod,
} from "../router/timeline-project-context-support.js";
import { buildTimelineProjectAssignmentConflicts } from "../router/timeline-project-conflict-support.js";
import {
  formatHolidayOverlays,
  loadTimelineHolidayOverlays,
} from "../router/timeline-holiday-read.js";

const loadTimelineHolidayOverlaysMock = vi.mocked(loadTimelineHolidayOverlays);
const formatHolidayOverlaysMock = vi.mocked(formatHolidayOverlays);

describe("timeline project context support", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("derives the detail period from explicit input and validates order", () => {
    expect(resolveTimelineProjectContextPeriod({
      requestedStartDate: "2026-04-03",
      requestedEndDate: "2026-04-12",
      projectStartDate: new Date("2026-04-01T00:00:00.000Z"),
      projectEndDate: new Date("2026-04-10T00:00:00.000Z"),
    })).toEqual({
      startDate: new Date("2026-04-03T00:00:00.000Z"),
      endDate: new Date("2026-04-12T00:00:00.000Z"),
    });

    expect(() =>
      resolveTimelineProjectContextPeriod({
        requestedStartDate: "2026-04-12",
        requestedEndDate: "2026-04-03",
      }),
    ).toThrowError(new TRPCError({
      code: "BAD_REQUEST",
      message: "endDate must be on or after startDate.",
    }));
  });

  it("builds assignment conflict summaries with cross-project overlap counts", () => {
    expect(buildTimelineProjectAssignmentConflicts({
      projectId: "project_1",
      assignments: [
        {
          id: "assignment_1",
          resourceId: "resource_1",
          resource: { displayName: "Alice" },
          startDate: new Date("2026-04-01T00:00:00.000Z"),
          endDate: new Date("2026-04-05T00:00:00.000Z"),
          hoursPerDay: 8,
        },
        {
          id: "placeholder_1",
          resourceId: null,
          resource: null,
          startDate: new Date("2026-04-01T00:00:00.000Z"),
          endDate: new Date("2026-04-05T00:00:00.000Z"),
          hoursPerDay: 4,
        },
      ],
      allResourceAllocations: [
        {
          id: "assignment_1",
          resourceId: "resource_1",
          projectId: "project_1",
          project: { name: "Current", shortCode: "CUR" },
          startDate: new Date("2026-04-01T00:00:00.000Z"),
          endDate: new Date("2026-04-05T00:00:00.000Z"),
          hoursPerDay: 8,
          status: "ACTIVE",
        },
        {
          id: "booking_2",
          resourceId: "resource_1",
          projectId: "project_2",
          project: { name: "Other", shortCode: "OTH" },
          startDate: new Date("2026-04-04T00:00:00.000Z"),
          endDate: new Date("2026-04-07T00:00:00.000Z"),
          hoursPerDay: 6,
          status: "ACTIVE",
        },
        {
          id: "booking_3",
          resourceId: "resource_1",
          projectId: "project_1",
          project: { name: "Current", shortCode: "CUR" },
          startDate: new Date("2026-04-02T00:00:00.000Z"),
          endDate: new Date("2026-04-03T00:00:00.000Z"),
          hoursPerDay: 2,
          status: "PROPOSED",
        },
      ],
    })).toEqual([
      {
        assignmentId: "assignment_1",
        resourceId: "resource_1",
        resourceName: "Alice",
        startDate: "2026-04-01",
        endDate: "2026-04-05",
        hoursPerDay: 8,
        overlapCount: 2,
        crossProjectOverlapCount: 1,
        overlaps: [
          {
            id: "booking_2",
            projectId: "project_2",
            projectName: "Other",
            projectShortCode: "OTH",
            startDate: "2026-04-04",
            endDate: "2026-04-07",
            hoursPerDay: 6,
            status: "ACTIVE",
            sameProject: false,
          },
          {
            id: "booking_3",
            projectId: "project_1",
            projectName: "Current",
            projectShortCode: "CUR",
            startDate: "2026-04-02",
            endDate: "2026-04-03",
            hoursPerDay: 2,
            status: "PROPOSED",
            sameProject: true,
          },
        ],
      },
    ]);
  });

  it("loads detail artifacts with formatted holiday overlays only when resources exist", async () => {
    loadTimelineHolidayOverlaysMock.mockResolvedValueOnce([
      {
        id: "overlay_1",
        resourceId: "resource_1",
        startDate: new Date("2026-04-03T00:00:00.000Z"),
        endDate: new Date("2026-04-03T00:00:00.000Z"),
        note: "Holiday",
        scope: "COUNTRY",
        calendarName: "DE",
        sourceType: "CALENDAR",
        countryCode: "DE",
        countryName: "Germany",
        federalState: null,
        metroCityName: null,
      },
    ] as never);

    const artifacts = await loadTimelineProjectContextDetailArtifacts({} as never, {
      projectId: "project_1",
      requestedStartDate: "2026-04-01",
      durationDays: 5,
      projectStartDate: new Date("2026-04-01T00:00:00.000Z"),
      projectEndDate: new Date("2026-04-10T00:00:00.000Z"),
      firstAssignmentStartDate: new Date("2026-04-02T00:00:00.000Z"),
      firstDemandStartDate: new Date("2026-04-01T00:00:00.000Z"),
      assignments: [
        {
          id: "assignment_1",
          resourceId: "resource_1",
          resource: { displayName: "Alice" },
          startDate: new Date("2026-04-01T00:00:00.000Z"),
          endDate: new Date("2026-04-05T00:00:00.000Z"),
          hoursPerDay: 8,
        },
      ],
      allResourceAllocations: [
        {
          id: "booking_1",
          resourceId: "resource_1",
          projectId: "project_2",
          project: { name: "Other", shortCode: "OTH" },
          startDate: new Date("2026-04-04T00:00:00.000Z"),
          endDate: new Date("2026-04-07T00:00:00.000Z"),
          hoursPerDay: 6,
          status: "ACTIVE",
        },
      ],
      resourceIds: ["resource_1"],
    });

    expect(loadTimelineHolidayOverlaysMock).toHaveBeenCalledWith(
      {},
      {
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-10T00:00:00.000Z"),
        resourceIds: ["resource_1"],
        projectIds: ["project_1"],
      },
    );
    expect(formatHolidayOverlaysMock).toHaveBeenCalledTimes(1);
    expect(artifacts).toEqual({
      period: {
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-10T00:00:00.000Z"),
      },
      holidayOverlays: [
        {
          id: "overlay_1",
          resourceId: "resource_1",
          startDate: "2026-04-03",
          endDate: "2026-04-03",
          note: "Holiday",
          scope: "COUNTRY",
          calendarName: "DE",
          sourceType: "CALENDAR",
          countryCode: "DE",
          countryName: "Germany",
          federalState: null,
          metroCityName: null,
        },
      ],
      assignmentConflicts: [
        {
          assignmentId: "assignment_1",
          resourceId: "resource_1",
          resourceName: "Alice",
          startDate: "2026-04-01",
          endDate: "2026-04-05",
          hoursPerDay: 8,
          overlapCount: 1,
          crossProjectOverlapCount: 1,
          overlaps: [
            {
              id: "booking_1",
              projectId: "project_2",
              projectName: "Other",
              projectShortCode: "OTH",
              startDate: "2026-04-04",
              endDate: "2026-04-07",
              hoursPerDay: 6,
              status: "ACTIVE",
              sameProject: false,
            },
          ],
        },
      ],
    });

    const emptyArtifacts = await loadTimelineProjectContextDetailArtifacts({} as never, {
      projectId: "project_1",
      requestedStartDate: "2026-04-01",
      durationDays: 5,
      assignments: [],
      allResourceAllocations: [],
      resourceIds: [],
    });

    expect(loadTimelineHolidayOverlaysMock).toHaveBeenCalledTimes(1);
    expect(emptyArtifacts.holidayOverlays).toEqual([]);
    expect(emptyArtifacts.assignmentConflicts).toEqual([]);
  });
});
