/**
 * Get Global Leaderboards Use Case
 *
 * Orchestrates the retrieval of global leaderboards data.
 * Aggregates data from repositories and returns top drivers and teams.
 */

import { LeaderboardsRepository } from '../ports/LeaderboardsRepository';
import { LeaderboardsEventPublisher } from '../ports/LeaderboardsEventPublisher';
import {
  GlobalLeaderboardsQuery,
  GlobalLeaderboardsResult,
  GlobalLeaderboardDriverEntry,
  GlobalLeaderboardTeamEntry,
} from '../ports/GlobalLeaderboardsQuery';

export interface GetGlobalLeaderboardsUseCasePorts {
  leaderboardsRepository: LeaderboardsRepository;
  eventPublisher: LeaderboardsEventPublisher;
}

export class GetGlobalLeaderboardsUseCase {
  constructor(private readonly ports: GetGlobalLeaderboardsUseCasePorts) {}

  async execute(query: GlobalLeaderboardsQuery = {}): Promise<GlobalLeaderboardsResult> {
    try {
      const driverLimit = query.driverLimit ?? 10;
      const teamLimit = query.teamLimit ?? 10;

      // Fetch all drivers and teams in parallel
      const [allDrivers, allTeams] = await Promise.all([
        this.ports.leaderboardsRepository.findAllDrivers(),
        this.ports.leaderboardsRepository.findAllTeams(),
      ]);

      // Sort drivers by rating (highest first) and take top N
      const topDrivers = allDrivers
        .sort((a, b) => {
          const ratingComparison = b.rating - a.rating;
          if (ratingComparison === 0) {
            return a.name.localeCompare(b.name);
          }
          return ratingComparison;
        })
        .slice(0, driverLimit)
        .map((driver, index): GlobalLeaderboardDriverEntry => ({
          rank: index + 1,
          id: driver.id,
          name: driver.name,
          rating: driver.rating,
          ...(driver.teamId !== undefined && { teamId: driver.teamId }),
          ...(driver.teamName !== undefined && { teamName: driver.teamName }),
          raceCount: driver.raceCount,
        }));

      // Sort teams by rating (highest first) and take top N
      const topTeams = allTeams
        .sort((a, b) => {
          const ratingComparison = b.rating - a.rating;
          if (ratingComparison === 0) {
            return a.name.localeCompare(b.name);
          }
          return ratingComparison;
        })
        .slice(0, teamLimit)
        .map((team, index): GlobalLeaderboardTeamEntry => ({
          rank: index + 1,
          id: team.id,
          name: team.name,
          rating: team.rating,
          memberCount: team.memberCount,
          raceCount: team.raceCount,
        }));

      // Publish event
      await this.ports.eventPublisher.publishGlobalLeaderboardsAccessed({
        type: 'global_leaderboards_accessed',
        timestamp: new Date(),
      });

      return {
        drivers: topDrivers,
        teams: topTeams,
      };
    } catch (error) {
      // Publish error event
      await this.ports.eventPublisher.publishLeaderboardsError({
        type: 'leaderboards_error',
        error: error instanceof Error ? error.message : String(error),
        timestamp: new Date(),
      });
      throw error;
    }
  }
}
