import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import {
  GetTotalLeaguesUseCase,
  type GetTotalLeaguesInput,
  type GetTotalLeaguesResult,
  type GetTotalLeaguesErrorCode,
} from './GetTotalLeaguesUseCase';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import type { UseCaseOutputPort } from '@core/shared/application';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';

describe('GetTotalLeaguesUseCase', () => {
  let useCase: GetTotalLeaguesUseCase;
  let leagueRepository: {
    findAll: Mock;
  };
  let output: UseCaseOutputPort<GetTotalLeaguesResult> & { present: Mock };

  beforeEach(() => {
    leagueRepository = {
      findAll: vi.fn(),
    };

    output = {
      present: vi.fn(),
    } as unknown as UseCaseOutputPort<GetTotalLeaguesResult> & { present: Mock };

    useCase = new GetTotalLeaguesUseCase(
      leagueRepository as unknown as ILeagueRepository,
      output,
    );
  });

  it('should return total number of leagues', async () => {
    const leagues = [
      { id: 'league-1', name: 'League 1' },
      { id: 'league-2', name: 'League 2' },
      { id: 'league-3', name: 'League 3' },
    ];

    leagueRepository.findAll.mockResolvedValue(leagues);

    const input: GetTotalLeaguesInput = {};

    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toBeUndefined();
    expect(output.present).toHaveBeenCalledTimes(1);
    expect(output.present).toHaveBeenCalledWith<Parameters<UseCaseOutputPort<GetTotalLeaguesResult>['present']>>({
      totalLeagues: 3,
    });
  });

  it('should return error on repository failure', async () => {
    const repositoryError = new Error('Repository error');

    leagueRepository.findAll.mockRejectedValue(repositoryError);

    const input: GetTotalLeaguesInput = {};

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);

    const error = result.unwrapErr() as ApplicationErrorCode<
      GetTotalLeaguesErrorCode,
      { message: string }
    >;

    expect(error.code).toBe('REPOSITORY_ERROR');
    expect(error.details.message).toBe('Repository error');
    expect(output.present).not.toHaveBeenCalled();
  });
});