import { describe, it, expect, vi, beforeEach } from 'vitest';
import { GetLeagueFullConfigUseCase } from './GetLeagueFullConfigUseCase';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { ILeagueScoringConfigRepository } from '../../domain/repositories/ILeagueScoringConfigRepository';
import type { IGameRepository } from '../../domain/repositories/IGameRepository';
import type { ILeagueFullConfigPresenter, LeagueConfigFormViewModel } from '../presenters/ILeagueFullConfigPresenter';

describe('GetLeagueFullConfigUseCase', () => {
  let useCase: GetLeagueFullConfigUseCase;
  let leagueRepository: ILeagueRepository;
  let seasonRepository: ISeasonRepository;
  let leagueScoringConfigRepository: ILeagueScoringConfigRepository;
  let gameRepository: IGameRepository;
  let presenter: ILeagueFullConfigPresenter;

  beforeEach(() => {
    leagueRepository = {
      findById: vi.fn(),
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any;
    seasonRepository = {
      findByLeagueId: vi.fn(),
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any;
    leagueScoringConfigRepository = {
      findBySeasonId: vi.fn(),
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any;
    gameRepository = {
      findById: vi.fn(),
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any;
    presenter = {
      reset: vi.fn(),
      present: vi.fn(),
      getViewModel: vi.fn(),
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } as any;

    useCase = new GetLeagueFullConfigUseCase(
      leagueRepository,
      seasonRepository,
      leagueScoringConfigRepository,
      gameRepository,
      presenter,
    );
  });

  it('should return league config when league exists', async () => {
    const params = { leagueId: 'league-1' };

    const mockLeague = {
      id: 'league-1',
      name: 'Test League',
      description: 'A test league',
      settings: {
        maxDrivers: 32,
        stewarding: {
          decisionMode: 'admin_only',
          requireDefense: false,
          defenseTimeLimit: 48,
          voteTimeLimit: 72,
          protestDeadlineHours: 48,
          stewardingClosesHours: 168,
          notifyAccusedOnProtest: true,
          notifyOnVoteRequired: true,
        },
      },
    };
    const mockSeasons = [{ id: 'season-1', status: 'active', gameId: 'game-1' }];
    const mockScoringConfig = { id: 'config-1' };
    const mockGame = { id: 'game-1' };
    const mockViewModel: LeagueConfigFormViewModel = {
      leagueId: 'league-1',
      basics: {
        name: 'Test League',
        description: 'A test league',
        visibility: 'public',
        gameId: 'iracing',
      },
      structure: {
        mode: 'solo',
        maxDrivers: 32,
        multiClassEnabled: false,
      },
      championships: {
        enableDriverChampionship: true,
        enableTeamChampionship: false,
        enableNationsChampionship: false,
        enableTrophyChampionship: false,
      },
      scoring: {
        customScoringEnabled: false,
      },
      dropPolicy: {
        strategy: 'none',
      },
      timings: {
        practiceMinutes: 30,
        qualifyingMinutes: 15,
        mainRaceMinutes: 60,
        sessionCount: 1,
        roundsPlanned: 10,
      },
      stewarding: {
        decisionMode: 'admin_only',
        requireDefense: false,
        defenseTimeLimit: 48,
        voteTimeLimit: 72,
        protestDeadlineHours: 48,
        stewardingClosesHours: 168,
        notifyAccusedOnProtest: true,
        notifyOnVoteRequired: true,
      },
    };

    leagueRepository.findById.mockResolvedValue(mockLeague);
    seasonRepository.findByLeagueId.mockResolvedValue(mockSeasons);
    leagueScoringConfigRepository.findBySeasonId.mockResolvedValue(mockScoringConfig);
    gameRepository.findById.mockResolvedValue(mockGame);
    presenter.getViewModel.mockReturnValue(mockViewModel);

    const result = await useCase.execute(params);

    expect(result.isOk()).toBe(true);
    const viewModel = result.value!;
    expect(viewModel).toEqual(mockViewModel);
    expect(presenter.reset).toHaveBeenCalled();
    expect(presenter.present).toHaveBeenCalledWith({
      league: mockLeague,
      activeSeason: mockSeasons[0],
      scoringConfig: mockScoringConfig,
      game: mockGame,
    });
  });

  it('should return error when league not found', async () => {
    const params = { leagueId: 'league-1' };

    leagueRepository.findById.mockResolvedValue(null);

    const result = await useCase.execute(params);

    expect(result.isErr()).toBe(true);
    const error = result.unwrapErr();
    expect(error.code).toBe('LEAGUE_NOT_FOUND');
    expect(error.details!.message).toBe('League with id league-1 not found');
  });

  it('should handle no active season', async () => {
    const params = { leagueId: 'league-1' };

    const mockLeague = {
      id: 'league-1',
      name: 'Test League',
      description: 'A test league',
      settings: { maxDrivers: 32 },
    };
    const mockViewModel: LeagueConfigFormViewModel = {
      leagueId: 'league-1',
      basics: { name: 'Test League', description: 'A test league', visibility: 'public', gameId: 'iracing' },
      structure: { mode: 'solo', maxDrivers: 32, multiClassEnabled: false },
      championships: { enableDriverChampionship: true, enableTeamChampionship: false, enableNationsChampionship: false, enableTrophyChampionship: false },
      scoring: { customScoringEnabled: false },
      dropPolicy: { strategy: 'none' },
      timings: { practiceMinutes: 30, qualifyingMinutes: 15, mainRaceMinutes: 60, sessionCount: 1, roundsPlanned: 10 },
      stewarding: { decisionMode: 'admin_only', requireDefense: false, defenseTimeLimit: 48, voteTimeLimit: 72, protestDeadlineHours: 48, stewardingClosesHours: 168, notifyAccusedOnProtest: true, notifyOnVoteRequired: true },
    };

    leagueRepository.findById.mockResolvedValue(mockLeague);
    seasonRepository.findByLeagueId.mockResolvedValue([]);
    presenter.getViewModel.mockReturnValue(mockViewModel);

    const result = await useCase.execute(params);

    expect(result.isOk()).toBe(true);
    expect(presenter.present).toHaveBeenCalledWith({
      league: mockLeague,
    });
  });
});