import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetLeagueStatsUseCase } from './GetLeagueStatsUseCase';
import { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
import { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import { DriverRatingProvider } from '../ports/DriverRatingProvider';

describe('GetLeagueStatsUseCase', () => {
  let useCase: GetLeagueStatsUseCase;
  let leagueMembershipRepository: {
    getLeagueMembers: Mock;
  };
  let raceRepository: {
    findByLeagueId: Mock;
  };
  let driverRatingProvider: {
    getRatings: Mock;
  };

  beforeEach(() => {
    leagueMembershipRepository = {
      getLeagueMembers: vi.fn(),
    };
    raceRepository = {
      findByLeagueId: vi.fn(),
    };
    driverRatingProvider = {
      getRatings: vi.fn(),
    };
    useCase = new GetLeagueStatsUseCase(
      leagueMembershipRepository as unknown as ILeagueMembershipRepository,
      raceRepository as unknown as IRaceRepository,
      driverRatingProvider as unknown as DriverRatingProvider,
    );
  });

  it('should return league stats with average rating', async () => {
    const leagueId = 'league-1';
    const memberships = [
      { driverId: 'driver-1' },
      { driverId: 'driver-2' },
      { driverId: 'driver-3' },
    ];
    const races = [{ id: 'race-1' }, { id: 'race-2' }];
    const ratings = new Map([
      ['driver-1', 1500],
      ['driver-2', 1600],
      ['driver-3', null],
    ]);

    leagueMembershipRepository.getLeagueMembers.mockResolvedValue(memberships);
    raceRepository.findByLeagueId.mockResolvedValue(races);
    driverRatingProvider.getRatings.mockReturnValue(ratings);

    const result = await useCase.execute({ leagueId });

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toEqual({
      totalMembers: 3,
      totalRaces: 2,
      averageRating: 1550, // (1500 + 1600) / 2
    });
  });

  it('should return 0 average rating when no valid ratings', async () => {
    const leagueId = 'league-1';
    const memberships = [{ driverId: 'driver-1' }];
    const races = [{ id: 'race-1' }];
    const ratings = new Map([['driver-1', null]]);

    leagueMembershipRepository.getLeagueMembers.mockResolvedValue(memberships);
    raceRepository.findByLeagueId.mockResolvedValue(races);
    driverRatingProvider.getRatings.mockReturnValue(ratings);

    const result = await useCase.execute({ leagueId });

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toEqual({
      totalMembers: 1,
      totalRaces: 1,
      averageRating: 0,
    });
  });

  it('should return error when repository fails', async () => {
    const leagueId = 'league-1';
    leagueMembershipRepository.getLeagueMembers.mockRejectedValue(new Error('DB error'));

    const result = await useCase.execute({ leagueId });

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr()).toEqual({
      code: 'REPOSITORY_ERROR',
      message: 'Failed to fetch league stats',
    });
  });
});