/**
 * Application Use Case: TeamRankingUseCase
 * 
 * Computes team rankings from rating snapshots (ledger-based).
 * Orchestrates repositories to provide team ranking data to presentation layer.
 * Evolved from direct standings to use team rating events and snapshots.
 */

import type { Logger } from '@core/shared/application';
import type { ITeamRatingRepository } from '../../domain/repositories/ITeamRatingRepository';
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
import type { ITeamRankingUseCase, TeamRanking } from './ITeamRankingUseCase';

export class TeamRankingUseCase implements ITeamRankingUseCase {
  constructor(
    private readonly teamRatingRepository: ITeamRatingRepository,
    private readonly teamRepository: ITeamRepository,
    private readonly logger: Logger
  ) {
    this.logger.info('[TeamRankingUseCase] Initialized with ledger-based team rating repositories');
  }

  async getAllTeamRankings(): Promise<TeamRanking[]> {
    this.logger.debug('[TeamRankingUseCase] Computing rankings from team rating snapshots');

    try {
      // Get all teams for name resolution
      const teams = await this.teamRepository.findAll();
      const teamMap = new Map(teams.map(t => [t.id, t]));

      // Get all team IDs
      const teamIds = Array.from(teamMap.keys());

      if (teamIds.length === 0) {
        this.logger.warn('[TeamRankingUseCase] No teams found');
        return [];
      }

      // Get rating snapshots for all teams
      const rankingPromises = teamIds.map(async (teamId) => {
        const snapshot = await this.teamRatingRepository.findByTeamId(teamId);
        const team = teamMap.get(teamId);
        
        if (!snapshot || !team) {
          return null;
        }

        return {
          teamId,
          teamName: team.name.toString(),
          drivingRating: snapshot.driving.value,
          adminTrustRating: snapshot.adminTrust.value,
          overallRating: snapshot.overall,
          eventCount: snapshot.eventCount,
          lastUpdated: snapshot.lastUpdated,
          overallRank: null, // Will be assigned after sorting
        } as TeamRanking;
      });

      const rankings = (await Promise.all(rankingPromises)).filter(
        (r): r is TeamRanking => r !== null
      );

      if (rankings.length === 0) {
        this.logger.warn('[TeamRankingUseCase] No team rating snapshots found');
        return [];
      }

      // Sort by overall rating descending and assign ranks
      rankings.sort((a, b) => b.overallRating - a.overallRating);
      rankings.forEach((r, idx) => r.overallRank = idx + 1);

      this.logger.info(`[TeamRankingUseCase] Computed rankings for ${rankings.length} teams`);

      return rankings;
    } catch (error) {
      this.logger.error('[TeamRankingUseCase] Error computing rankings:', error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async getTeamRanking(teamId: string): Promise<TeamRanking | null> {
    this.logger.debug(`[TeamRankingUseCase] Getting ranking for team ${teamId}`);

    try {
      const snapshot = await this.teamRatingRepository.findByTeamId(teamId);
      
      if (!snapshot) {
        this.logger.warn(`[TeamRankingUseCase] No rating snapshot found for team ${teamId}`);
        return null;
      }

      const team = await this.teamRepository.findById(teamId);
      
      if (!team) {
        this.logger.warn(`[TeamRankingUseCase] Team ${teamId} not found`);
        return null;
      }

      // Get all teams to calculate rank
      const allTeams = await this.teamRepository.findAll();
      const allRankings: TeamRanking[] = [];

      for (const t of allTeams) {
        const s = await this.teamRatingRepository.findByTeamId(t.id);
        if (s) {
          allRankings.push({
            teamId: t.id,
            teamName: t.name.toString(),
            drivingRating: s.driving.value,
            adminTrustRating: s.adminTrust.value,
            overallRating: s.overall,
            eventCount: s.eventCount,
            lastUpdated: s.lastUpdated,
            overallRank: null,
          });
        }
      }

      // Sort and assign rank
      allRankings.sort((a, b) => b.overallRating - a.overallRating);
      const rank = allRankings.findIndex(r => r.teamId === teamId) + 1;

      return {
        teamId,
        teamName: team.name.toString(),
        drivingRating: snapshot.driving.value,
        adminTrustRating: snapshot.adminTrust.value,
        overallRating: snapshot.overall,
        eventCount: snapshot.eventCount,
        lastUpdated: snapshot.lastUpdated,
        overallRank: rank,
      };
    } catch (error) {
      this.logger.error(`[TeamRankingUseCase] Error getting team ranking:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }
}