import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { Test, TestingModule } from "@nestjs/testing";
import { JobEventsController } from "./job-events.controller";
import { JobEventsService } from "./job-events.service";
import { JOB_CREATED } from "./event-types";
import { AuthGuard } from "../auth/guards/auth.guard";
import { WorkspaceGuard } from "../common/guards/workspace.guard";
import { PermissionGuard } from "../common/guards/permission.guard";
import { ExecutionContext } from "@nestjs/common";

describe("JobEventsController", () => {
  let controller: JobEventsController;
  let service: JobEventsService;

  const mockJobEventsService = {
    getEventsByJobId: vi.fn(),
  };

  const mockAuthGuard = {
    canActivate: vi.fn((context: ExecutionContext) => {
      const request = context.switchToHttp().getRequest();
      request.user = {
        id: "user-123",
        workspaceId: "workspace-123",
      };
      return true;
    }),
  };

  const mockWorkspaceGuard = {
    canActivate: vi.fn(() => true),
  };

  const mockPermissionGuard = {
    canActivate: vi.fn(() => true),
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [JobEventsController],
      providers: [
        {
          provide: JobEventsService,
          useValue: mockJobEventsService,
        },
      ],
    })
      .overrideGuard(AuthGuard)
      .useValue(mockAuthGuard)
      .overrideGuard(WorkspaceGuard)
      .useValue(mockWorkspaceGuard)
      .overrideGuard(PermissionGuard)
      .useValue(mockPermissionGuard)
      .compile();

    controller = module.get<JobEventsController>(JobEventsController);
    service = module.get<JobEventsService>(JobEventsService);
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  describe("getEvents", () => {
    const jobId = "job-123";
    const workspaceId = "workspace-123";
    const mockEvents = {
      data: [
        {
          id: "event-1",
          jobId,
          stepId: null,
          type: JOB_CREATED,
          timestamp: new Date("2026-01-01T10:00:00Z"),
          actor: "system",
          payload: {},
        },
      ],
      meta: {
        total: 1,
        page: 1,
        limit: 50,
        totalPages: 1,
      },
    };

    it("should return paginated events for a job", async () => {
      mockJobEventsService.getEventsByJobId.mockResolvedValue(mockEvents);

      const result = await controller.getEvents(jobId, {}, workspaceId);

      expect(service.getEventsByJobId).toHaveBeenCalledWith(jobId, {});
      expect(result).toEqual(mockEvents);
    });

    it("should pass query parameters to service", async () => {
      const query = { type: JOB_CREATED, page: 2, limit: 10 };
      mockJobEventsService.getEventsByJobId.mockResolvedValue(mockEvents);

      await controller.getEvents(jobId, query, workspaceId);

      expect(service.getEventsByJobId).toHaveBeenCalledWith(jobId, query);
    });

    it("should handle filtering by type", async () => {
      const query = { type: JOB_CREATED };
      mockJobEventsService.getEventsByJobId.mockResolvedValue(mockEvents);

      const result = await controller.getEvents(jobId, query, workspaceId);

      expect(service.getEventsByJobId).toHaveBeenCalledWith(jobId, query);
      expect(result).toEqual(mockEvents);
    });

    it("should handle pagination parameters", async () => {
      const query = { page: 2, limit: 25 };
      mockJobEventsService.getEventsByJobId.mockResolvedValue({
        ...mockEvents,
        meta: {
          total: 100,
          page: 2,
          limit: 25,
          totalPages: 4,
        },
      });

      const result = await controller.getEvents(jobId, query, workspaceId);

      expect(service.getEventsByJobId).toHaveBeenCalledWith(jobId, query);
      expect(result.meta.page).toBe(2);
      expect(result.meta.limit).toBe(25);
    });
  });
});
