import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetLeagueProtestsUseCase } from './GetLeagueProtestsUseCase';
import { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import { IProtestRepository } from '../../domain/repositories/IProtestRepository';
import { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import { Race } from '../../domain/entities/Race';
import { Protest } from '../../domain/entities/Protest';
import { Driver } from '../../domain/entities/Driver';

describe('GetLeagueProtestsUseCase', () => {
  let useCase: GetLeagueProtestsUseCase;
  let raceRepository: {
    findByLeagueId: Mock;
  };
  let protestRepository: {
    findByRaceId: Mock;
  };
  let driverRepository: {
    findById: Mock;
  };

  beforeEach(() => {
    raceRepository = {
      findByLeagueId: vi.fn(),
    };
    protestRepository = {
      findByRaceId: vi.fn(),
    };
    driverRepository = {
      findById: vi.fn(),
    };
    useCase = new GetLeagueProtestsUseCase(
      raceRepository as unknown as IRaceRepository,
      protestRepository as unknown as IProtestRepository,
      driverRepository as unknown as IDriverRepository,
    );
  });

  it('should return protests with races and drivers', async () => {
    const leagueId = 'league-1';
    const race = Race.create({
      id: 'race-1',
      leagueId,
      scheduledAt: new Date(),
      track: 'Track 1',
      car: 'Car 1',
    });
    const protest = Protest.create({
      id: 'protest-1',
      raceId: 'race-1',
      protestingDriverId: 'driver-1',
      accusedDriverId: 'driver-2',
      incident: { lap: 1, description: 'Incident' },
      status: 'pending',
      filedAt: new Date(),
    });
    const driver1 = Driver.create({
      id: 'driver-1',
      iracingId: '123',
      name: 'Driver 1',
      country: 'US',
    });
    const driver2 = Driver.create({
      id: 'driver-2',
      iracingId: '456',
      name: 'Driver 2',
      country: 'UK',
    });

    raceRepository.findByLeagueId.mockResolvedValue([race]);
    protestRepository.findByRaceId.mockResolvedValue([protest]);
    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({
      protests: [
        {
          id: 'protest-1',
          raceId: 'race-1',
          protestingDriverId: 'driver-1',
          accusedDriverId: 'driver-2',
          submittedAt: expect.any(Date),
          description: '',
          status: 'pending',
        },
      ],
      races: [
        {
          id: 'race-1',
          name: 'Track 1',
          date: expect.any(String),
        },
      ],
      drivers: [
        { id: 'driver-1', name: 'Driver 1' },
        { id: 'driver-2', name: 'Driver 2' },
      ],
    });
  });

  it('should return empty when no races', async () => {
    const leagueId = 'league-1';

    raceRepository.findByLeagueId.mockResolvedValue([]);
    protestRepository.findByRaceId.mockResolvedValue([]);

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

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toEqual({
      protests: [],
      races: [],
      drivers: [],
    });
  });
});