import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import type { GameRepository } from '../../domain/repositories/GameRepository';
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
import type { LeagueScoringConfigRepository } from '../../domain/repositories/LeagueScoringConfigRepository';
import type { SeasonRepository } from '../../domain/repositories/SeasonRepository';
import {
    GetLeagueFullConfigUseCase,
    type GetLeagueFullConfigErrorCode,
    type GetLeagueFullConfigInput,
} from './GetLeagueFullConfigUseCase';

describe('GetLeagueFullConfigUseCase', () => {
  let useCase: GetLeagueFullConfigUseCase;
  let leagueRepository: { findById: Mock };
  let seasonRepository: { findByLeagueId: Mock };
  let leagueScoringConfigRepository: { findBySeasonId: Mock };
  let gameRepository: { findById: Mock };

  beforeEach(() => {
    leagueRepository = {
      findById: vi.fn(),
    };
    seasonRepository = {
      findByLeagueId: vi.fn(),
    };
    leagueScoringConfigRepository = {
      findBySeasonId: vi.fn(),
    };
    gameRepository = {
      findById: vi.fn(),
    };

    useCase = new GetLeagueFullConfigUseCase(
      leagueRepository as unknown as LeagueRepository,
      seasonRepository as unknown as SeasonRepository,
      leagueScoringConfigRepository as unknown as LeagueScoringConfigRepository,
      gameRepository as unknown as GameRepository
    );
  });

  it('should return league config when league exists', async () => {
    const input: GetLeagueFullConfigInput = { 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: { isActive: () => true }, gameId: 'game-1' }];
    const mockScoringConfig = { id: 'config-1' };
    const mockGame = { id: 'game-1' };

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

    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const presented = result.unwrap();

    expect(presented.config.league).toEqual(mockLeague);
    expect(presented.config.activeSeason).toEqual(mockSeasons[0]);
    expect(presented.config.scoringConfig).toEqual(mockScoringConfig);
    expect(presented.config.game).toEqual(mockGame);
  });

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

    leagueRepository.findById.mockResolvedValue(null);

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);
    const error = result.unwrapErr() as ApplicationErrorCode<
      GetLeagueFullConfigErrorCode,
      { message: string }
    >;

    expect(error.code).toBe('LEAGUE_NOT_FOUND');
    expect(error.details.message).toBe('League not found');
  });

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

    const mockLeague = {
      id: 'league-1',
      name: 'Test League',
      description: 'A test league',
      settings: { maxDrivers: 32 },
    };

    leagueRepository.findById.mockResolvedValue(mockLeague);
    seasonRepository.findByLeagueId.mockResolvedValue([]);

    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const presented = result.unwrap();

    expect(presented.config.league).toEqual(mockLeague);
    expect(presented.config.activeSeason).toBeUndefined();
    expect(presented.config.scoringConfig).toBeUndefined();
    expect(presented.config.game).toBeUndefined();
  });

  it('should return repository error when repository throws', async () => {
    const input: GetLeagueFullConfigInput = { leagueId: 'league-1' };

    const thrownError = new Error('Repository failure');
    leagueRepository.findById.mockRejectedValue(thrownError);

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);
    const error = result.unwrapErr() as ApplicationErrorCode<
      GetLeagueFullConfigErrorCode,
      { message: string }
    >;

    expect(error.code).toBe('REPOSITORY_ERROR');
    expect(error.details.message).toBe('Repository failure');
  });
});
