import { Test, TestingModule } from "@nestjs/testing";
import { describe, it, expect, beforeEach, vi } from "vitest";
import { TeamMemberRole } from "@prisma/client";
import { AuthGuard } from "../auth/guards/auth.guard";
import { PermissionGuard, WorkspaceGuard } from "../common/guards";
import { TeamsController } from "./teams.controller";
import { TeamsService } from "./teams.service";

describe("TeamsController", () => {
  let controller: TeamsController;
  let service: TeamsService;

  const mockTeamsService = {
    create: vi.fn(),
    findAll: vi.fn(),
    addMember: vi.fn(),
    removeMember: vi.fn(),
    remove: vi.fn(),
  };

  const mockWorkspaceId = "550e8400-e29b-41d4-a716-446655440001";
  const mockTeamId = "550e8400-e29b-41d4-a716-446655440002";
  const mockUserId = "550e8400-e29b-41d4-a716-446655440003";

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [TeamsController],
      providers: [
        {
          provide: TeamsService,
          useValue: mockTeamsService,
        },
      ],
    })
      .overrideGuard(AuthGuard)
      .useValue({ canActivate: vi.fn(() => true) })
      .overrideGuard(WorkspaceGuard)
      .useValue({ canActivate: vi.fn(() => true) })
      .overrideGuard(PermissionGuard)
      .useValue({ canActivate: vi.fn(() => true) })
      .compile();

    controller = module.get<TeamsController>(TeamsController);
    service = module.get<TeamsService>(TeamsService);

    vi.clearAllMocks();
  });

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

  describe("create", () => {
    it("should create a team in a workspace", async () => {
      const createDto = {
        name: "Platform Team",
        description: "Owns platform services",
      };

      const createdTeam = {
        id: mockTeamId,
        workspaceId: mockWorkspaceId,
        name: createDto.name,
        description: createDto.description,
        metadata: {},
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      mockTeamsService.create.mockResolvedValue(createdTeam);

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

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

  describe("findAll", () => {
    it("should list teams in a workspace", async () => {
      const teams = [
        {
          id: mockTeamId,
          workspaceId: mockWorkspaceId,
          name: "Platform Team",
          description: "Owns platform services",
          metadata: {},
          createdAt: new Date(),
          updatedAt: new Date(),
          _count: { members: 2 },
        },
      ];

      mockTeamsService.findAll.mockResolvedValue(teams);

      const result = await controller.findAll(mockWorkspaceId);

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

  describe("addMember", () => {
    it("should add a member to a team", async () => {
      const dto = {
        userId: mockUserId,
        role: TeamMemberRole.ADMIN,
      };

      const createdTeamMember = {
        teamId: mockTeamId,
        userId: mockUserId,
        role: TeamMemberRole.ADMIN,
        joinedAt: new Date(),
        user: {
          id: mockUserId,
          name: "Test User",
          email: "test@example.com",
        },
      };

      mockTeamsService.addMember.mockResolvedValue(createdTeamMember);

      const result = await controller.addMember(mockTeamId, dto, mockWorkspaceId);

      expect(result).toEqual(createdTeamMember);
      expect(service.addMember).toHaveBeenCalledWith(mockWorkspaceId, mockTeamId, dto);
    });
  });

  describe("removeMember", () => {
    it("should remove a member from a team", async () => {
      mockTeamsService.removeMember.mockResolvedValue(undefined);

      await controller.removeMember(mockTeamId, mockUserId, mockWorkspaceId);

      expect(service.removeMember).toHaveBeenCalledWith(mockWorkspaceId, mockTeamId, mockUserId);
    });
  });

  describe("remove", () => {
    it("should delete a team", async () => {
      mockTeamsService.remove.mockResolvedValue(undefined);

      await controller.remove(mockTeamId, mockWorkspaceId);

      expect(service.remove).toHaveBeenCalledWith(mockWorkspaceId, mockTeamId);
    });
  });
});
