import { Result } from '@core/shared/domain/Result';
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 { 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 type { LeagueScoringPreset } from '../../domain/types/LeagueScoringPreset';

export interface GetLeagueScoringConfigInput {
  leagueId: string;
}

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

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

export class GetLeagueScoringConfigUseCase {
  constructor(
    private readonly leagueRepository: LeagueRepository,
    private readonly seasonRepository: SeasonRepository,
    private readonly leagueScoringConfigRepository: LeagueScoringConfigRepository,
    private readonly gameRepository: GameRepository,
    private readonly presetProvider: {
      getPresetById(presetId: string): LeagueScoringPreset | undefined;
    },
  ) {}

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

    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;
        });

      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 } : {}),
      };

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