import { beforeAll, beforeEach, describe, expect, it, afterAll, vi } from "vitest";
import { randomUUID as uuid } from "crypto";
import { Test, TestingModule } from "@nestjs/testing";
import { PrismaClient } from "@prisma/client";
import { TasksService } from "./tasks.service";
import { PrismaService } from "../prisma/prisma.service";
import { ActivityService } from "../activity/activity.service";

const shouldRunDbIntegrationTests =
  process.env.RUN_DB_TESTS === "true" && Boolean(process.env.DATABASE_URL);
const describeFn = shouldRunDbIntegrationTests ? describe : describe.skip;

describeFn("TasksService assignedAgent Integration", () => {
  let moduleRef: TestingModule;
  let prisma: PrismaClient;
  let service: TasksService;
  let workspaceId: string;
  let ownerId: string;
  let setupComplete = false;

  const activityServiceMock = {
    logTaskCreated: vi.fn().mockResolvedValue(undefined),
    logTaskUpdated: vi.fn().mockResolvedValue(undefined),
    logTaskDeleted: vi.fn().mockResolvedValue(undefined),
    logTaskCompleted: vi.fn().mockResolvedValue(undefined),
    logTaskAssigned: vi.fn().mockResolvedValue(undefined),
  };

  beforeAll(async () => {
    prisma = new PrismaClient();
    await prisma.$connect();

    const workspace = await prisma.workspace.create({
      data: {
        name: `Tasks Assigned Agent Integration ${Date.now()}`,
        owner: {
          create: {
            email: `tasks-assigned-agent-integration-${Date.now()}@example.com`,
            name: "Tasks Assigned Agent Integration Owner",
          },
        },
      },
    });

    workspaceId = workspace.id;
    ownerId = workspace.ownerId;

    moduleRef = await Test.createTestingModule({
      providers: [
        TasksService,
        {
          provide: PrismaService,
          useValue: prisma,
        },
        {
          provide: ActivityService,
          useValue: activityServiceMock,
        },
      ],
    }).compile();

    service = moduleRef.get<TasksService>(TasksService);
    setupComplete = true;
  });

  beforeEach(async () => {
    vi.clearAllMocks();

    if (!setupComplete) {
      return;
    }

    await prisma.task.deleteMany({ where: { workspaceId } });
  });

  afterAll(async () => {
    if (!prisma) {
      return;
    }

    if (workspaceId) {
      await prisma.task.deleteMany({ where: { workspaceId } });
      await prisma.workspace.deleteMany({ where: { id: workspaceId } });
    }
    if (ownerId) {
      await prisma.user.deleteMany({ where: { id: ownerId } });
    }

    if (moduleRef) {
      await moduleRef.close();
    }
    await prisma.$disconnect();
  });

  it("persists assignedAgent on create", async () => {
    if (!setupComplete) {
      return;
    }

    const task = await service.create(workspaceId, ownerId, {
      title: `Assigned agent create ${uuid()}`,
      assignedAgent: "fleet-worker-1",
    });

    expect(task.assignedAgent).toBe("fleet-worker-1");

    const stored = await prisma.task.findUnique({
      where: {
        id: task.id,
      },
      select: {
        id: true,
        assignedAgent: true,
      },
    });

    expect(stored).toMatchObject({
      id: task.id,
      assignedAgent: "fleet-worker-1",
    });

    const listed = await service.findAll({ workspaceId, page: 1, limit: 10 }, ownerId);
    const listedTask = listed.data.find((row) => row.id === task.id);

    expect(listedTask?.assignedAgent).toBe("fleet-worker-1");
  });

  it("updates and clears assignedAgent", async () => {
    if (!setupComplete) {
      return;
    }

    const created = await service.create(workspaceId, ownerId, {
      title: `Assigned agent update ${uuid()}`,
    });

    expect(created.assignedAgent).toBeNull();

    const updated = await service.update(created.id, workspaceId, ownerId, {
      assignedAgent: "fleet-worker-2",
    });

    expect(updated.assignedAgent).toBe("fleet-worker-2");

    const cleared = await service.update(created.id, workspaceId, ownerId, {
      assignedAgent: null,
    });

    expect(cleared.assignedAgent).toBeNull();

    const stored = await prisma.task.findUnique({
      where: {
        id: created.id,
      },
      select: {
        assignedAgent: true,
      },
    });

    expect(stored?.assignedAgent).toBeNull();
  });
});
