import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetLeagueStandingsUseCase } from './GetLeagueStandingsUseCase';
import { IStandingRepository } from '../../domain/repositories/IStandingRepository';
import { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import { Standing } from '../../domain/entities/Standing';
import { Driver } from '../../domain/entities/Driver';

describe('GetLeagueStandingsUseCase', () => {
  let useCase: GetLeagueStandingsUseCase;
  let standingRepository: {
    findByLeagueId: Mock;
  };
  let driverRepository: {
    findById: Mock;
  };

  beforeEach(() => {
    standingRepository = {
      findByLeagueId: vi.fn(),
    };
    driverRepository = {
      findById: vi.fn(),
    };
    useCase = new GetLeagueStandingsUseCase(
      standingRepository as unknown as IStandingRepository,
      driverRepository as unknown as IDriverRepository,
    );
  });

  it('should return standings with drivers mapped', async () => {
    const leagueId = 'league-1';
    const standings = [
      Standing.create({
        id: 'standing-1',
        leagueId,
        driverId: 'driver-1',
        points: 100,
        position: 1,
      }),
      Standing.create({
        id: 'standing-2',
        leagueId,
        driverId: 'driver-2',
        points: 80,
        position: 2,
      }),
    ];
    const driver1 = Driver.create({
      id: 'driver-1',
      iracingId: '123',
      name: 'Driver One',
      country: 'US',
    });
    const driver2 = Driver.create({
      id: 'driver-2',
      iracingId: '456',
      name: 'Driver Two',
      country: 'US',
    });

    standingRepository.findByLeagueId.mockResolvedValue(standings);
    driverRepository.findById.mockImplementation((id: string) => {
      if (id === 'driver-1') return Promise.resolve(driver1);
      if (id === 'driver-2') return Promise.resolve(driver2);
      return Promise.resolve(null);
    });

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

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toEqual({
      standings: [
        {
          driverId: 'driver-1',
          driver: { id: 'driver-1', name: 'Driver One' },
          points: 100,
          rank: 1,
        },
        {
          driverId: 'driver-2',
          driver: { id: 'driver-2', name: 'Driver Two' },
          points: 80,
          rank: 2,
        },
      ],
    });
  });

  it('should return error when repository fails', async () => {
    const leagueId = 'league-1';
    standingRepository.findByLeagueId.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 standings',
    });
  });
});