import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import { Season } from '../../domain/entities/season/Season';
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
import type { SeasonRepository } from '../../domain/repositories/SeasonRepository';
import {
    ListSeasonsForLeagueUseCase,
    type ListSeasonsForLeagueErrorCode,
    type ListSeasonsForLeagueInput,
} from './ListSeasonsForLeagueUseCase';


describe('ListSeasonsForLeagueUseCase', () => {
  let useCase: ListSeasonsForLeagueUseCase;
  let leagueRepository: {
    exists: Mock;
  };
  let seasonRepository: {
    findByLeagueId: Mock;
  };
  beforeEach(() => {
    leagueRepository = {
      exists: vi.fn(),
    };
    seasonRepository = {
      findByLeagueId: vi.fn(),
    };
    useCase = new ListSeasonsForLeagueUseCase(
      seasonRepository as unknown as SeasonRepository,
      leagueRepository as unknown as LeagueRepository
    );
  });

  it('lists seasons for a league with domain entities and returns them in result', async () => {
    const leagueId = 'league-1';
    const seasons = [
      Season.create({
        id: 'season-1',
        leagueId,
        gameId: 'iracing',
        name: 'Season One',
        status: 'planned',
      }),
      Season.create({
        id: 'season-2',
        leagueId,
        gameId: 'iracing',
        name: 'Season Two',
        status: 'active',
      }),
    ];

    leagueRepository.exists.mockResolvedValue(true);
    seasonRepository.findByLeagueId.mockResolvedValue(seasons);

    const input: ListSeasonsForLeagueInput = { leagueId };

    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const value = result.unwrap();
    expect(value.seasons).toHaveLength(2);
    const resultIds = value.seasons.map((s) => s.id).sort();
    expect(resultIds).toEqual(['season-1', 'season-2']);

    const firstSeason = value.seasons.find((s) => s.id === 'season-1');
    const secondSeason = value.seasons.find((s) => s.id === 'season-2');

    expect(firstSeason?.name).toBe('Season One');
    expect(firstSeason?.status.toString()).toBe('planned');
    expect(secondSeason?.name).toBe('Season Two');
    expect(secondSeason?.status.toString()).toBe('active');
  });

  it('returns error when league not found and does not call output', async () => {
    leagueRepository.exists.mockResolvedValue(false);

    const input: ListSeasonsForLeagueInput = { leagueId: 'league-1' };

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);
    const error = result.unwrapErr() as ApplicationErrorCode<
      ListSeasonsForLeagueErrorCode,
      { message: string }
    >;
    expect(error.code).toBe('LEAGUE_NOT_FOUND');
    expect(error.details.message).toContain('League not found');
  });

  it('wraps repository failures and does not call output', async () => {
    const leagueId = 'league-1';
    const thrown = new Error('DB is down');

    leagueRepository.exists.mockResolvedValue(true);
    seasonRepository.findByLeagueId.mockRejectedValue(thrown);

    const input: ListSeasonsForLeagueInput = { leagueId };

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);
    const error = result.unwrapErr() as ApplicationErrorCode<
      ListSeasonsForLeagueErrorCode,
      { message: string }
    >;
    expect(error.code).toBe('REPOSITORY_ERROR');
    expect(error.details.message).toBe('DB is down');
  });
});