import type { UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Driver } from '../../domain/entities/Driver';
import type { IStandingRepository } from '../../domain/repositories/IStandingRepository';
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';

export type GetLeagueStandingsErrorCode = 'REPOSITORY_ERROR';

export type GetLeagueStandingsInput = {
  leagueId: string;
};

export type LeagueStandingItem = {
  driverId: string;
  driver: Driver;
  points: number;
  rank: number;
};

export type GetLeagueStandingsResult = {
  standings: LeagueStandingItem[];
};

/**
 * Use Case for retrieving league standings.
 */
export class GetLeagueStandingsUseCase {
  constructor(
    private readonly standingRepository: IStandingRepository,
    private readonly driverRepository: IDriverRepository,
    private readonly output: UseCaseOutputPort<GetLeagueStandingsResult>,
  ) {}

  async execute(
    input: GetLeagueStandingsInput,
  ): Promise<
    Result<void, ApplicationErrorCode<GetLeagueStandingsErrorCode, { message: string }>>
  > {
    try {
      const standings = await this.standingRepository.findByLeagueId(input.leagueId);
      const driverIds = [...new Set(standings.map(s => s.driverId.toString()))];
      const driverPromises = driverIds.map(id => this.driverRepository.findById(id));
      const driverResults = await Promise.all(driverPromises);
      const drivers = driverResults.filter(
        (driver): driver is NonNullable<(typeof driverResults)[number]> => driver !== null,
      );
      const driverMap = new Map(drivers.map(driver => [driver.id, driver]));

      const result: GetLeagueStandingsResult = {
        standings: standings.map(standing => ({
          driverId: standing.driverId.toString(),
          driver: driverMap.get(standing.driverId.toString())!,
          points: standing.points.toNumber(),
          rank: standing.position.toNumber(),
        })),
      };

      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 fetch league standings',
        },
      });
    }
  }
}