import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository'; import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository'; import type { LeagueDTO } from '../dto/LeagueDTO'; export class GetAllLeaguesWithCapacityQuery { constructor( private readonly leagueRepository: ILeagueRepository, private readonly leagueMembershipRepository: ILeagueMembershipRepository, ) {} async execute(): Promise { const leagues = await this.leagueRepository.findAll(); const results: LeagueDTO[] = []; for (const league of leagues) { const members = await this.leagueMembershipRepository.getLeagueMembers(league.id); const usedSlots = members.filter( (m) => m.status === 'active' && (m.role === 'owner' || m.role === 'admin' || m.role === 'steward' || m.role === 'member'), ).length; // Ensure we never expose an impossible state like 26/24: // clamp maxDrivers to at least usedSlots at the application boundary. const configuredMax = league.settings.maxDrivers ?? usedSlots; const safeMaxDrivers = Math.max(configuredMax, usedSlots); const dto: LeagueDTO = { id: league.id, name: league.name, description: league.description, ownerId: league.ownerId, settings: { ...league.settings, maxDrivers: safeMaxDrivers, }, createdAt: league.createdAt.toISOString(), socialLinks: league.socialLinks ? { discordUrl: league.socialLinks.discordUrl, youtubeUrl: league.socialLinks.youtubeUrl, websiteUrl: league.socialLinks.websiteUrl, } : undefined, usedSlots, }; results.push(dto); } return results; } }