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 { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';

export interface GetLeagueJoinRequestsInput {
  leagueId: string;
}

export type GetLeagueJoinRequestsErrorCode = 'LEAGUE_NOT_FOUND' | 'REPOSITORY_ERROR';

export interface LeagueJoinRequestWithDriver {
  id: string;
  leagueId: string;
  driverId: string;
  requestedAt: Date;
  message?: string;
  driver: Driver;
}

export interface GetLeagueJoinRequestsResult {
  joinRequests: LeagueJoinRequestWithDriver[];
}

export class GetLeagueJoinRequestsUseCase {
  constructor(
    private readonly leagueMembershipRepository: ILeagueMembershipRepository,
    private readonly driverRepository: IDriverRepository,
    private readonly leagueRepository: ILeagueRepository,
    private readonly output: UseCaseOutputPort<GetLeagueJoinRequestsResult>,
  ) {}

  async execute(
    input: GetLeagueJoinRequestsInput,
  ): Promise<Result<void, ApplicationErrorCode<GetLeagueJoinRequestsErrorCode, { message: string }>>> {
    try {
      const leagueExists = await this.leagueRepository.exists(input.leagueId);

      if (!leagueExists) {
        return Result.err({
          code: 'LEAGUE_NOT_FOUND',
          details: { message: 'League not found' },
        });
      }

      const joinRequests = await this.leagueMembershipRepository.getJoinRequests(input.leagueId);
      const driverIds = [...new Set(joinRequests.map(request => request.driverId.toString()))];
      const drivers = await Promise.all(driverIds.map(id => this.driverRepository.findById(id)));

      const driverMap = new Map(
        drivers.filter((driver): driver is Driver => driver !== null).map(driver => [driver.id, driver]),
      );

      const enrichedJoinRequests: LeagueJoinRequestWithDriver[] = joinRequests
        .filter(request => driverMap.has(request.driverId.toString()))
        .map(request => ({
          id: request.id,
          leagueId: request.leagueId.toString(),
          driverId: request.driverId.toString(),
          requestedAt: request.requestedAt.toDate(),
          ...(request.message !== undefined && { message: request.message }),
          driver: driverMap.get(request.driverId.toString())!,
        }));

      const result: GetLeagueJoinRequestsResult = {
        joinRequests: enrichedJoinRequests,
      };

      this.output.present(result);

      return Result.ok(undefined);
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Failed to load league join requests';

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message },
      });
    }
  }
}
