import { describe, it, expect, beforeEach, vi } from 'vitest';
import { GetAllTeamsUseCase } from './GetAllTeamsUseCase';
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import type { Logger } from '@core/shared/application';

describe('GetAllTeamsUseCase', () => {
  const mockTeamFindAll = vi.fn();
  const mockTeamRepo: ITeamRepository = {
    findById: vi.fn(),
    findAll: mockTeamFindAll,
    findByLeagueId: vi.fn(),
    create: vi.fn(),
    update: vi.fn(),
    delete: vi.fn(),
    exists: vi.fn(),
  };

  const mockTeamMembershipCountByTeamId = vi.fn();
  const mockTeamMembershipRepo: ITeamMembershipRepository = {
    getMembership: vi.fn(),
    getActiveMembershipForDriver: vi.fn(),
    getTeamMembers: vi.fn(),
    saveMembership: vi.fn(),
    removeMembership: vi.fn(),
    countByTeamId: mockTeamMembershipCountByTeamId,
    getJoinRequests: vi.fn(),
    saveJoinRequest: vi.fn(),
    removeJoinRequest: vi.fn(),
  };

  const mockLogger: Logger = {
    debug: vi.fn(),
    info: vi.fn(),
    warn: vi.fn(),
    error: vi.fn(),
  };

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

  it('should return teams data', async () => {
    const useCase = new GetAllTeamsUseCase(
      mockTeamRepo,
      mockTeamMembershipRepo,
      mockLogger,
    );

    const team1 = {
      id: 'team1',
      name: 'Team One',
      tag: 'TO',
      description: 'Description One',
      ownerId: 'owner1',
      leagues: ['league1'],
      createdAt: new Date('2023-01-01T00:00:00Z'),
    };
    const team2 = {
      id: 'team2',
      name: 'Team Two',
      tag: 'TT',
      description: 'Description Two',
      ownerId: 'owner2',
      leagues: ['league2'],
      createdAt: new Date('2023-01-02T00:00:00Z'),
    };

    mockTeamFindAll.mockResolvedValue([team1, team2]);
    mockTeamMembershipCountByTeamId.mockImplementation((id: string) => Promise.resolve(id === 'team1' ? 5 : 3));

    const result = await useCase.execute();

    expect(result.isOk()).toBe(true);
    expect(result.value).toEqual({
      teams: [
        {
          id: 'team1',
          name: 'Team One',
          tag: 'TO',
          description: 'Description One',
          ownerId: 'owner1',
          leagues: ['league1'],
          createdAt: new Date('2023-01-01T00:00:00Z'),
          memberCount: 5,
        },
        {
          id: 'team2',
          name: 'Team Two',
          tag: 'TT',
          description: 'Description Two',
          ownerId: 'owner2',
          leagues: ['league2'],
          createdAt: new Date('2023-01-02T00:00:00Z'),
          memberCount: 3,
        },
      ],
    });
  });

  it('should return empty result when no teams', async () => {
    const useCase = new GetAllTeamsUseCase(
      mockTeamRepo,
      mockTeamMembershipRepo,
      mockLogger,
    );

    mockTeamFindAll.mockResolvedValue([]);

    const result = await useCase.execute();

    expect(result.isOk()).toBe(true);
    expect(result.value).toEqual({
      teams: [],
    });
  });

  it('should return error when repository throws', async () => {
    const useCase = new GetAllTeamsUseCase(
      mockTeamRepo,
      mockTeamMembershipRepo,
      mockLogger,
    );

    const error = new Error('Repository error');
    mockTeamFindAll.mockRejectedValue(error);

    const result = await useCase.execute();

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR');
    expect(result.unwrapErr().details.message).toBe('Repository error');
  });
});