import { Result } from '@core/shared/application/Result';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Game } from '../../domain/entities/Game';
import type { League } from '../../domain/entities/League';
import type { LeagueScoringConfig } from '../../domain/entities/LeagueScoringConfig';
import type { Season } from '../../domain/entities/season/Season';
import type { IGameRepository } from '../../domain/repositories/IGameRepository';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import type { ILeagueScoringConfigRepository } from '../../domain/repositories/ILeagueScoringConfigRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { LeagueScoringPreset } from '../../domain/types/LeagueScoringPreset';

export type GetLeagueScoringConfigInput = {
  leagueId: string;
};

export type GetLeagueScoringConfigResult = {
  league: League;
  season: Season;
  scoringConfig: LeagueScoringConfig;
  game: Game;
  preset?: LeagueScoringPreset;
};

export type GetLeagueScoringConfigErrorCode =
  | 'LEAGUE_NOT_FOUND'
  | 'NO_SEASONS'
  | 'NO_ACTIVE_SEASON'
  | 'NO_SCORING_CONFIG'
  | 'GAME_NOT_FOUND'
  | 'REPOSITORY_ERROR';

/**
 * Use Case for retrieving a league's scoring configuration for its active season.
 */
export class GetLeagueScoringConfigUseCase {
  constructor(
    private readonly leagueRepository: ILeagueRepository,
    private readonly seasonRepository: ISeasonRepository,
    private readonly leagueScoringConfigRepository: ILeagueScoringConfigRepository,
    private readonly gameRepository: IGameRepository,
    private readonly presetProvider: {
      getPresetById(presetId: string): LeagueScoringPreset | undefined;
    },
    private readonly output: UseCaseOutputPort<GetLeagueScoringConfigResult>,
  ) {}

  async execute(
    params: GetLeagueScoringConfigInput,
  ): Promise<
    Result<void, ApplicationErrorCode<GetLeagueScoringConfigErrorCode, { message: string }>>
  > {
    const { leagueId } = params;

    try {
      const league = await this.leagueRepository.findById(leagueId);
      if (!league) {
        return Result.err({
          code: 'LEAGUE_NOT_FOUND',
          details: { message: 'League not found' },
        });
      }

      const seasons = await this.seasonRepository.findByLeagueId(leagueId);
      if (!seasons || seasons.length === 0) {
        return Result.err({
          code: 'NO_SEASONS',
          details: { message: 'No seasons found for league' },
        });
      }

      const activeSeason =
        seasons.find((s) => {
          const seasonStatus = (s as unknown as { status?: unknown }).status;
          if (typeof seasonStatus === 'string') return seasonStatus === 'active';
          if (seasonStatus && typeof (seasonStatus as { isActive?: unknown }).isActive === 'function') {
            return (seasonStatus as { isActive: () => boolean }).isActive();
          }
          if (seasonStatus && typeof (seasonStatus as { toString?: unknown }).toString === 'function') {
            return (seasonStatus as { toString: () => string }).toString() === 'active';
          }
          return false;
        }) ?? seasons[0];

      if (!activeSeason) {
        return Result.err({
          code: 'NO_ACTIVE_SEASON',
          details: { message: 'No active season found for league' },
        });
      }

      const scoringConfig =
        await this.leagueScoringConfigRepository.findBySeasonId(
          activeSeason.id,
        );
      if (!scoringConfig) {
        return Result.err({
          code: 'NO_SCORING_CONFIG',
          details: { message: 'Scoring configuration not found' },
        });
      }

      const game = await this.gameRepository.findById(activeSeason.gameId);
      if (!game) {
        return Result.err({
          code: 'GAME_NOT_FOUND',
          details: { message: 'Game not found for season' },
        });
      }

      const presetId = scoringConfig.scoringPresetId;
      const preset = presetId
        ? this.presetProvider.getPresetById(presetId.toString())
        : undefined;

      const result: GetLeagueScoringConfigResult = {
        league,
        season: activeSeason,
        scoringConfig,
        game,
        ...(preset !== undefined ? { preset } : {}),
      };

      this.output.present(result);

      return Result.ok(undefined);
    } catch (error) {
      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: {
          message:
            error instanceof Error
              ? error.message
              : 'Failed to load league scoring config',
        },
      });
    }
  }
}