import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository'; import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository'; import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository'; import type { TeamsLeaderboardOutputPort, SkillLevel } from '../ports/output/TeamsLeaderboardOutputPort'; import { SkillLevelService } from '@core/racing/domain/services/SkillLevelService'; import { Result } from '@core/shared/application/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { AsyncUseCase } from '@core/shared/application'; import type { Logger } from '@core/shared/application'; interface DriverStatsAdapter { rating: number | null; wins: number; totalRaces: number; } interface TeamLeaderboardItem { id: string; name: string; memberCount: number; rating: number | null; totalWins: number; totalRaces: number; performanceLevel: string; isRecruiting: boolean; createdAt: Date; description: string; } /** * Use case: GetTeamsLeaderboardUseCase */ export class GetTeamsLeaderboardUseCase implements AsyncUseCase { constructor( private readonly teamRepository: ITeamRepository, private readonly teamMembershipRepository: ITeamMembershipRepository, private readonly driverRepository: IDriverRepository, private readonly getDriverStats: (driverId: string) => DriverStatsAdapter | null, private readonly logger: Logger, ) {} async execute(): Promise>> { try { const allTeams = await this.teamRepository.findAll(); const teams: TeamLeaderboardItem[] = []; await Promise.all( allTeams.map(async (team) => { const memberships = await this.teamMembershipRepository.getTeamMembers(team.id); const memberCount = memberships.length; let ratingSum = 0; let ratingCount = 0; let totalWins = 0; let totalRaces = 0; for (const membership of memberships) { const stats = this.getDriverStats(membership.driverId); if (!stats) continue; if (typeof stats.rating === 'number') { ratingSum += stats.rating; ratingCount += 1; } totalWins += stats.wins ?? 0; totalRaces += stats.totalRaces ?? 0; } const averageRating = ratingCount > 0 ? ratingSum / ratingCount : null; const performanceLevel = SkillLevelService.getTeamPerformanceLevel(averageRating); teams.push({ id: team.id, name: team.name, memberCount, rating: averageRating, totalWins, totalRaces, performanceLevel, isRecruiting: true, createdAt: new Date(), description: team.description, }); }) ); const recruitingCount = teams.filter((t) => t.isRecruiting).length; const groupsBySkillLevel: Record = { beginner: [], intermediate: [], advanced: [], pro: [], }; teams.forEach(team => { const level = team.performanceLevel as SkillLevel; groupsBySkillLevel[level].push(team); }); const topTeams = teams.slice(0, 10); // Assuming top 10 const outputPort: TeamsLeaderboardOutputPort = { teams, recruitingCount, groupsBySkillLevel, topTeams, }; return Result.ok(outputPort); } catch (error) { this.logger.error('Error retrieving teams leaderboard', error as Error); return Result.err({ code: 'REPOSITORY_ERROR', details: { message: 'Failed to retrieve teams leaderboard' } }); } } }