import { describe, expect, it, vi } from 'vitest';
import { RaceService } from './RaceService';

describe('RaceService', () => {
  it('invokes each use case and returns the corresponding presenter', async () => {
    const mkUseCase = () => ({ execute: vi.fn(async () => {}) });

    const getAllRacesUseCase = mkUseCase();
    const getTotalRacesUseCase = mkUseCase();
    const importRaceResultsApiUseCase = mkUseCase();
    const getRaceDetailUseCase = mkUseCase();
    const getRacesPageDataUseCase = mkUseCase();
    const getAllRacesPageDataUseCase = mkUseCase();
    const getRaceResultsDetailUseCase = mkUseCase();
    const getRaceWithSOFUseCase = mkUseCase();
    const getRaceProtestsUseCase = mkUseCase();
    const getRacePenaltiesUseCase = mkUseCase();
    const registerForRaceUseCase = mkUseCase();
    const withdrawFromRaceUseCase = mkUseCase();
    const cancelRaceUseCase = mkUseCase();
    const completeRaceUseCase = mkUseCase();
    const fileProtestUseCase = mkUseCase();
    const quickPenaltyUseCase = mkUseCase();
    const applyPenaltyUseCase = mkUseCase();
    const requestProtestDefenseUseCase = mkUseCase();
    const reviewProtestUseCase = mkUseCase();
    const reopenRaceUseCase = mkUseCase();

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

    const getAllRacesPresenter = {} as any;
    const getTotalRacesPresenter = {} as any;
    const importRaceResultsApiPresenter = {} as any;
    const raceDetailPresenter = {} as any;
    const racesPageDataPresenter = {} as any;
    const allRacesPageDataPresenter = {} as any;
    const raceResultsDetailPresenter = {} as any;
    const raceWithSOFPresenter = {} as any;
    const raceProtestsPresenter = {} as any;
    const racePenaltiesPresenter = {} as any;
    const commandResultPresenter = {} as any;

    const service = new RaceService(
      getAllRacesUseCase as any,
      getTotalRacesUseCase as any,
      importRaceResultsApiUseCase as any,
      getRaceDetailUseCase as any,
      getRacesPageDataUseCase as any,
      getAllRacesPageDataUseCase as any,
      getRaceResultsDetailUseCase as any,
      getRaceWithSOFUseCase as any,
      getRaceProtestsUseCase as any,
      getRacePenaltiesUseCase as any,
      registerForRaceUseCase as any,
      withdrawFromRaceUseCase as any,
      cancelRaceUseCase as any,
      completeRaceUseCase as any,
      fileProtestUseCase as any,
      quickPenaltyUseCase as any,
      applyPenaltyUseCase as any,
      requestProtestDefenseUseCase as any,
      reviewProtestUseCase as any,
      reopenRaceUseCase as any,
      logger as any,
      getAllRacesPresenter,
      getTotalRacesPresenter,
      importRaceResultsApiPresenter,
      raceDetailPresenter,
      racesPageDataPresenter,
      allRacesPageDataPresenter,
      raceResultsDetailPresenter,
      raceWithSOFPresenter,
      raceProtestsPresenter,
      racePenaltiesPresenter,
      commandResultPresenter,
    );

    expect(await service.getAllRaces()).toBe(getAllRacesPresenter);
    expect(getAllRacesUseCase.execute).toHaveBeenCalledWith({});

    expect(await service.getTotalRaces()).toBe(getTotalRacesPresenter);
    expect(getTotalRacesUseCase.execute).toHaveBeenCalledWith({});

    expect(await service.importRaceResults({ raceId: 'r1', resultsFileContent: 'x' } as any)).toBe(importRaceResultsApiPresenter);
    expect(importRaceResultsApiUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', resultsFileContent: 'x' });

    expect(await service.getRaceDetail({ raceId: 'r1' } as any)).toBe(raceDetailPresenter);
    expect(getRaceDetailUseCase.execute).toHaveBeenCalled();

    expect(await service.getRacesPageData('l1')).toBe(racesPageDataPresenter);
    expect(getRacesPageDataUseCase.execute).toHaveBeenCalledWith({ leagueId: 'l1' });

    expect(await service.getAllRacesPageData()).toBe(allRacesPageDataPresenter);
    expect(getAllRacesPageDataUseCase.execute).toHaveBeenCalledWith({});

    expect(await service.getRaceResultsDetail('r1')).toBe(raceResultsDetailPresenter);
    expect(getRaceResultsDetailUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });

    expect(await service.getRaceWithSOF('r1')).toBe(raceWithSOFPresenter);
    expect(getRaceWithSOFUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });

    expect(await service.getRaceProtests('r1')).toBe(raceProtestsPresenter);
    expect(getRaceProtestsUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });

    expect(await service.getRacePenalties('r1')).toBe(racePenaltiesPresenter);
    expect(getRacePenaltiesUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });

    expect(await service.registerForRace({ raceId: 'r1', driverId: 'd1' } as any)).toBe(commandResultPresenter);
    expect(registerForRaceUseCase.execute).toHaveBeenCalled();

    expect(await service.withdrawFromRace({ raceId: 'r1', driverId: 'd1' } as any)).toBe(commandResultPresenter);
    expect(withdrawFromRaceUseCase.execute).toHaveBeenCalled();

    expect(await service.cancelRace({ raceId: 'r1' } as any, 'admin')).toBe(commandResultPresenter);
    expect(cancelRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', cancelledById: 'admin' });

    expect(await service.completeRace({ raceId: 'r1' } as any)).toBe(commandResultPresenter);
    expect(completeRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1' });

    expect(await service.reopenRace({ raceId: 'r1' } as any, 'admin')).toBe(commandResultPresenter);
    expect(reopenRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', reopenedById: 'admin' });

    expect(await service.fileProtest({} as any)).toBe(commandResultPresenter);
    expect(fileProtestUseCase.execute).toHaveBeenCalled();

    expect(await service.applyQuickPenalty({} as any)).toBe(commandResultPresenter);
    expect(quickPenaltyUseCase.execute).toHaveBeenCalled();

    expect(await service.applyPenalty({} as any)).toBe(commandResultPresenter);
    expect(applyPenaltyUseCase.execute).toHaveBeenCalled();

    expect(await service.requestProtestDefense({} as any)).toBe(commandResultPresenter);
    expect(requestProtestDefenseUseCase.execute).toHaveBeenCalled();

    expect(await service.reviewProtest({} as any)).toBe(commandResultPresenter);
    expect(reviewProtestUseCase.execute).toHaveBeenCalled();
  });
});
