import { beforeEach, describe, expect, it, vi } from "vitest";

vi.mock("@capakraken/application", () => ({
  buildSplitAllocationReadModel: vi.fn(),
  createAssignment: vi.fn(),
}));

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

import {
  buildSplitAllocationReadModel,
  createAssignment,
} from "@capakraken/application";
import { emitAllocationCreated } from "../sse/event-bus.js";
import {
  createTimelineBatchQuickAssignments,
  createTimelineQuickAssignment,
} from "../router/timeline-allocation-assignment-procedure-support.js";

const buildSplitAllocationReadModelMock = vi.mocked(buildSplitAllocationReadModel);
const createAssignmentMock = vi.mocked(createAssignment);
const emitAllocationCreatedMock = vi.mocked(emitAllocationCreated);

describe("timeline allocation assignment procedure support", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("creates a quick assignment and emits the allocation created event", async () => {
    const db = {
      $transaction: vi.fn(async (callback: (tx: unknown) => unknown) => callback(db)),
    } as never;

    createAssignmentMock.mockResolvedValueOnce({ id: "assignment_1" } as never);
    buildSplitAllocationReadModelMock.mockReturnValueOnce({
      allocations: [
        {
          id: "allocation_1",
          projectId: "project_1",
          resourceId: "resource_1",
        },
      ],
    } as never);

    await expect(
      createTimelineQuickAssignment(db, {
        resourceId: "resource_1",
        projectId: "project_1",
        startDate: new Date("2026-04-01T00:00:00.000Z"),
        endDate: new Date("2026-04-05T00:00:00.000Z"),
        hoursPerDay: 8,
        role: "Team Member",
        status: "PROPOSED",
        source: "quickAssign",
      }),
    ).resolves.toEqual({
      id: "allocation_1",
      projectId: "project_1",
      resourceId: "resource_1",
    });

    expect(createAssignmentMock).toHaveBeenCalledOnce();
    expect(emitAllocationCreatedMock).toHaveBeenCalledWith({
      id: "allocation_1",
      projectId: "project_1",
      resourceId: "resource_1",
    });
  });

  it("creates batch quick assignments and emits events for each result", async () => {
    const db = {
      $transaction: vi.fn(async (callback: (tx: unknown) => unknown) => callback(db)),
    } as never;

    createAssignmentMock
      .mockResolvedValueOnce({
        id: "assignment_1",
        projectId: "project_1",
        resourceId: "resource_1",
      } as never)
      .mockResolvedValueOnce({
        id: "assignment_2",
        projectId: "project_2",
        resourceId: "resource_2",
      } as never);

    await expect(
      createTimelineBatchQuickAssignments(db, {
        assignments: [
          {
            resourceId: "resource_1",
            projectId: "project_1",
            startDate: new Date("2026-04-01T00:00:00.000Z"),
            endDate: new Date("2026-04-05T00:00:00.000Z"),
            hoursPerDay: 8,
            role: "Team Member",
            status: "PROPOSED",
            source: "batchQuickAssign",
          },
          {
            resourceId: "resource_2",
            projectId: "project_2",
            startDate: new Date("2026-04-06T00:00:00.000Z"),
            endDate: new Date("2026-04-10T00:00:00.000Z"),
            hoursPerDay: 6,
            role: "Lead",
            status: "PROPOSED",
            source: "batchQuickAssign",
          },
        ],
      }),
    ).resolves.toEqual({ count: 2 });

    expect(createAssignmentMock).toHaveBeenCalledTimes(2);
    expect(emitAllocationCreatedMock).toHaveBeenNthCalledWith(1, {
      id: "assignment_1",
      projectId: "project_1",
      resourceId: "resource_1",
    });
    expect(emitAllocationCreatedMock).toHaveBeenNthCalledWith(2, {
      id: "assignment_2",
      projectId: "project_2",
      resourceId: "resource_2",
    });
  });
});
