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

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

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

  it("applies timeline project shifts through the real timeline router mutation", async () => {
    const { listAssignmentBookings } = await import("@capakraken/application");
    vi.mocked(listAssignmentBookings).mockResolvedValueOnce([]);

    const db = {
      project: {
        findUnique: vi.fn().mockResolvedValue({
          id: "project_1",
          name: "Gelddruckmaschine",
          shortCode: "GDM",
          status: "ACTIVE",
          responsiblePerson: null,
          budgetCents: 100000,
          winProbability: 100,
          startDate: new Date("2026-03-16"),
          endDate: new Date("2026-03-20"),
        }),
        update: vi.fn().mockResolvedValue({
          id: "project_1",
          startDate: new Date("2026-03-23"),
          endDate: new Date("2026-03-27"),
        }),
      },
      demandRequirement: {
        findMany: vi.fn().mockResolvedValue([]),
      },
      assignment: {
        findMany: vi.fn().mockResolvedValue([]),
      },
      auditLog: {
        create: vi.fn().mockResolvedValue({}),
      },
      $transaction: vi.fn(async (callback: (tx: unknown) => unknown) => callback(db)),
    };
    const ctx = createToolContext(
      db,
      [PermissionKey.MANAGE_ALLOCATIONS, PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS],
      SystemRole.MANAGER,
    );

    const result = await executeTool(
      "apply_timeline_project_shift",
      JSON.stringify({
        projectIdentifier: "project_1",
        newStartDate: "2026-03-23",
        newEndDate: "2026-03-27",
      }),
      ctx,
    );

    expect(result.action).toEqual({ type: "invalidate", scope: ["allocation", "timeline", "project"] });
    expect(JSON.parse(result.content)).toEqual(
      expect.objectContaining({
        success: true,
        project: expect.objectContaining({
          id: "project_1",
          startDate: "2026-03-23",
          endDate: "2026-03-27",
        }),
        validation: expect.objectContaining({
          valid: true,
        }),
      }),
    );
    expect(db.project.update).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { id: "project_1" },
      }),
    );
  });

  it("returns a stable project-not-found error if the timeline shift target disappears mid-mutation", async () => {
    const { listAssignmentBookings } = await import("@capakraken/application");
    vi.mocked(listAssignmentBookings).mockResolvedValueOnce([]);

    const db = {
      project: {
        findUnique: vi
          .fn()
          .mockResolvedValueOnce({
            id: "project_1",
            name: "Gelddruckmaschine",
            shortCode: "GDM",
            status: "ACTIVE",
            responsiblePerson: null,
            budgetCents: 100000,
            winProbability: 100,
            startDate: new Date("2026-03-16"),
            endDate: new Date("2026-03-20"),
          })
          .mockResolvedValueOnce(null),
      },
      demandRequirement: {
        findMany: vi.fn().mockResolvedValue([]),
      },
      assignment: {
        findMany: vi.fn().mockResolvedValue([]),
      },
    };
    const ctx = createToolContext(
      db,
      [PermissionKey.MANAGE_ALLOCATIONS, PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS],
      SystemRole.MANAGER,
    );

    const result = await executeTool(
      "apply_timeline_project_shift",
      JSON.stringify({
        projectIdentifier: "project_1",
        newStartDate: "2026-03-23",
        newEndDate: "2026-03-27",
      }),
      ctx,
    );

    expect(result.action).toBeUndefined();
    expect(JSON.parse(result.content)).toEqual({
      error: "Project not found with the given criteria.",
    });
  });
});
