import type { TeamMembership, TeamRole } from '@gridpilot/racing/domain/types/TeamMembership'; import type { DriverDTO } from '@gridpilot/racing/application/dto/DriverDTO'; import { EntityMappers } from '@gridpilot/racing/application/mappers/EntityMappers'; import { getDriverRepository, getDriverStats } from '@/lib/di-container'; export interface TeamRosterMemberViewModel { driver: DriverDTO; role: TeamRole; joinedAt: string; rating: number | null; overallRank: number | null; } export interface TeamRosterViewModel { members: TeamRosterMemberViewModel[]; averageRating: number; } /** * Presenter/facade for team roster. * Encapsulates repository and stats access so the TeamRoster component can remain a pure view. */ export async function getTeamRosterViewModel( memberships: TeamMembership[] ): Promise { const driverRepo = getDriverRepository(); const allDrivers = await driverRepo.findAll(); const members: TeamRosterMemberViewModel[] = []; for (const membership of memberships) { const driver = allDrivers.find((d) => d.id === membership.driverId); if (!driver) continue; const dto = EntityMappers.toDriverDTO(driver); if (!dto) continue; const stats = getDriverStats(membership.driverId); members.push({ driver: dto, role: membership.role, joinedAt: membership.joinedAt.toISOString(), rating: stats?.rating ?? null, overallRank: typeof stats?.overallRank === 'number' ? stats.overallRank : null, }); } const averageRating = members.length > 0 ? Math.round( members.reduce((sum, m) => sum + (m.rating ?? 0), 0) / members.length ) : 0; return { members, averageRating, }; }