import { describe, it, expect, beforeEach, vi } from "vitest";
import { Test, TestingModule } from "@nestjs/testing";
import { QualityGateConfigController } from "./quality-gate-config.controller";
import { QualityGateConfigService } from "./quality-gate-config.service";

describe("QualityGateConfigController", () => {
  let controller: QualityGateConfigController;
  let service: QualityGateConfigService;

  const mockService = {
    create: vi.fn(),
    findAll: vi.fn(),
    findEnabled: vi.fn(),
    findOne: vi.fn(),
    update: vi.fn(),
    delete: vi.fn(),
    reorder: vi.fn(),
    seedDefaults: vi.fn(),
  };

  const mockWorkspaceId = "550e8400-e29b-41d4-a716-446655440001";
  const mockGateId = "550e8400-e29b-41d4-a716-446655440002";

  const mockQualityGate = {
    id: mockGateId,
    workspaceId: mockWorkspaceId,
    name: "Build Check",
    description: "Verify code compiles without errors",
    type: "build",
    command: "pnpm build",
    expectedOutput: null,
    isRegex: false,
    required: true,
    order: 1,
    isEnabled: true,
    createdAt: new Date(),
    updatedAt: new Date(),
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [QualityGateConfigController],
      providers: [
        {
          provide: QualityGateConfigService,
          useValue: mockService,
        },
      ],
    }).compile();

    controller = module.get<QualityGateConfigController>(QualityGateConfigController);
    service = module.get<QualityGateConfigService>(QualityGateConfigService);

    vi.clearAllMocks();
  });

  it("should be defined", () => {
    expect(controller).toBeDefined();
  });

  describe("findAll", () => {
    it("should return all quality gates for a workspace", async () => {
      const mockGates = [mockQualityGate];
      mockService.findAll.mockResolvedValue(mockGates);

      const result = await controller.findAll(mockWorkspaceId);

      expect(result).toEqual(mockGates);
      expect(service.findAll).toHaveBeenCalledWith(mockWorkspaceId);
    });
  });

  describe("findOne", () => {
    it("should return a single quality gate", async () => {
      mockService.findOne.mockResolvedValue(mockQualityGate);

      const result = await controller.findOne(mockWorkspaceId, mockGateId);

      expect(result).toEqual(mockQualityGate);
      expect(service.findOne).toHaveBeenCalledWith(mockWorkspaceId, mockGateId);
    });
  });

  describe("create", () => {
    it("should create a new quality gate", async () => {
      const createDto = {
        name: "Build Check",
        description: "Verify code compiles without errors",
        type: "build" as const,
        command: "pnpm build",
        required: true,
        order: 1,
      };

      mockService.create.mockResolvedValue(mockQualityGate);

      const result = await controller.create(mockWorkspaceId, createDto);

      expect(result).toEqual(mockQualityGate);
      expect(service.create).toHaveBeenCalledWith(mockWorkspaceId, createDto);
    });
  });

  describe("update", () => {
    it("should update a quality gate", async () => {
      const updateDto = {
        name: "Updated Build Check",
        required: false,
      };

      const updatedGate = {
        ...mockQualityGate,
        ...updateDto,
      };

      mockService.update.mockResolvedValue(updatedGate);

      const result = await controller.update(mockWorkspaceId, mockGateId, updateDto);

      expect(result).toEqual(updatedGate);
      expect(service.update).toHaveBeenCalledWith(mockWorkspaceId, mockGateId, updateDto);
    });
  });

  describe("delete", () => {
    it("should delete a quality gate", async () => {
      mockService.delete.mockResolvedValue(undefined);

      await controller.delete(mockWorkspaceId, mockGateId);

      expect(service.delete).toHaveBeenCalledWith(mockWorkspaceId, mockGateId);
    });
  });

  describe("reorder", () => {
    it("should reorder quality gates", async () => {
      const gateIds = ["gate1", "gate2", "gate3"];
      const mockGates = gateIds.map((id, index) => ({
        ...mockQualityGate,
        id,
        order: index,
      }));

      mockService.reorder.mockResolvedValue(mockGates);

      const result = await controller.reorder(mockWorkspaceId, { gateIds });

      expect(result).toEqual(mockGates);
      expect(service.reorder).toHaveBeenCalledWith(mockWorkspaceId, gateIds);
    });
  });

  describe("seedDefaults", () => {
    it("should seed default quality gates", async () => {
      const mockGates = [mockQualityGate];
      mockService.seedDefaults.mockResolvedValue(mockGates);

      const result = await controller.seedDefaults(mockWorkspaceId);

      expect(result).toEqual(mockGates);
      expect(service.seedDefaults).toHaveBeenCalledWith(mockWorkspaceId);
    });
  });
});
