import { Injectable, Inject } from '@nestjs/common'; import { AllLeaguesWithCapacityViewModel, LeagueStatsDto, LeagueJoinRequestViewModel, ApproveJoinRequestInput, ApproveJoinRequestOutput, RejectJoinRequestInput, RejectJoinRequestOutput, LeagueAdminPermissionsViewModel, RemoveLeagueMemberInput, RemoveLeagueMemberOutput, UpdateLeagueMemberRoleInput, UpdateLeagueMemberRoleOutput, LeagueOwnerSummaryViewModel, LeagueConfigFormModelDto, LeagueAdminProtestsViewModel, LeagueSeasonSummaryViewModel, GetLeagueAdminPermissionsInput, GetLeagueProtestsQuery, GetLeagueSeasonsQuery, GetLeagueAdminConfigQuery, GetLeagueOwnerSummaryQuery, LeagueMembershipsViewModel, LeagueStandingsViewModel, LeagueScheduleViewModel, LeagueStatsViewModel, LeagueAdminViewModel, CreateLeagueInput, CreateLeagueOutput } from './dto/LeagueDto'; // Core imports import { Logger } from '@gridpilot/shared/application/Logger'; // Use cases import { GetAllLeaguesWithCapacityUseCase } from '@gridpilot/racing/application/use-cases/GetAllLeaguesWithCapacityUseCase'; import { GetLeagueStandingsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueStandingsUseCase'; import { GetLeagueStatsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueStatsUseCase'; import { GetLeagueFullConfigUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueFullConfigUseCase'; import { CreateLeagueWithSeasonAndScoringUseCase } from '@gridpilot/racing/application/use-cases/CreateLeagueWithSeasonAndScoringUseCase'; import { GetRaceProtestsUseCase } from '@gridpilot/racing/application/use-cases/GetRaceProtestsUseCase'; import { GetTotalLeaguesUseCase } from '@gridpilot/racing/application/use-cases/GetTotalLeaguesUseCase'; import { GetLeagueJoinRequestsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueJoinRequestsUseCase'; import { ApproveLeagueJoinRequestUseCase } from '@gridpilot/racing/application/use-cases/ApproveLeagueJoinRequestUseCase'; import { RejectLeagueJoinRequestUseCase } from '@gridpilot/racing/application/use-cases/RejectLeagueJoinRequestUseCase'; import { RemoveLeagueMemberUseCase } from '@gridpilot/racing/application/use-cases/RemoveLeagueMemberUseCase'; import { UpdateLeagueMemberRoleUseCase } from '@gridpilot/racing/application/use-cases/UpdateLeagueMemberRoleUseCase'; import { GetLeagueOwnerSummaryUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueOwnerSummaryUseCase'; import { GetLeagueProtestsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueProtestsUseCase'; import { GetLeagueSeasonsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueSeasonsUseCase'; import { GetLeagueMembershipsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueMembershipsUseCase'; import { GetLeagueScheduleUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueScheduleUseCase'; import { GetLeagueAdminPermissionsUseCase } from '@gridpilot/racing/application/use-cases/GetLeagueAdminPermissionsUseCase'; // API Presenters import { LeagueStandingsPresenter } from './presenters/LeagueStandingsPresenter'; import { AllLeaguesWithCapacityPresenter } from './presenters/AllLeaguesWithCapacityPresenter'; import { LeagueJoinRequestsPresenter } from './presenters/LeagueJoinRequestsPresenter'; import { ApproveLeagueJoinRequestPresenter } from './presenters/ApproveLeagueJoinRequestPresenter'; import { RejectLeagueJoinRequestPresenter } from './presenters/RejectLeagueJoinRequestPresenter'; import { RemoveLeagueMemberPresenter } from './presenters/RemoveLeagueMemberPresenter'; import { UpdateLeagueMemberRolePresenter } from './presenters/UpdateLeagueMemberRolePresenter'; import { GetLeagueOwnerSummaryPresenter } from './presenters/GetLeagueOwnerSummaryPresenter'; import { GetLeagueProtestsPresenter } from './presenters/GetLeagueProtestsPresenter'; import { GetLeagueSeasonsPresenter } from './presenters/GetLeagueSeasonsPresenter'; import { GetLeagueMembershipsPresenter } from './presenters/GetLeagueMembershipsPresenter'; import { LeagueSchedulePresenter } from './presenters/LeagueSchedulePresenter'; import { TotalLeaguesPresenter } from './presenters/TotalLeaguesPresenter'; import { LeagueConfigPresenter } from './presenters/LeagueConfigPresenter'; import { LeagueStatsPresenter } from './presenters/LeagueStatsPresenter'; import { GetLeagueAdminPermissionsPresenter } from './presenters/GetLeagueAdminPermissionsPresenter'; // Tokens import { LOGGER_TOKEN } from './LeagueProviders'; @Injectable() export class LeagueService { constructor( private readonly getAllLeaguesWithCapacityUseCase: GetAllLeaguesWithCapacityUseCase, private readonly getLeagueStandingsUseCase: GetLeagueStandingsUseCase, private readonly getLeagueStatsUseCase: GetLeagueStatsUseCase, private readonly getLeagueFullConfigUseCase: GetLeagueFullConfigUseCase, private readonly createLeagueWithSeasonAndScoringUseCase: CreateLeagueWithSeasonAndScoringUseCase, private readonly getRaceProtestsUseCase: GetRaceProtestsUseCase, private readonly getTotalLeaguesUseCase: GetTotalLeaguesUseCase, private readonly getLeagueJoinRequestsUseCase: GetLeagueJoinRequestsUseCase, private readonly approveLeagueJoinRequestUseCase: ApproveLeagueJoinRequestUseCase, private readonly rejectLeagueJoinRequestUseCase: RejectLeagueJoinRequestUseCase, private readonly removeLeagueMemberUseCase: RemoveLeagueMemberUseCase, private readonly updateLeagueMemberRoleUseCase: UpdateLeagueMemberRoleUseCase, private readonly getLeagueOwnerSummaryUseCase: GetLeagueOwnerSummaryUseCase, private readonly getLeagueProtestsUseCase: GetLeagueProtestsUseCase, private readonly getLeagueSeasonsUseCase: GetLeagueSeasonsUseCase, private readonly getLeagueMembershipsUseCase: GetLeagueMembershipsUseCase, private readonly getLeagueScheduleUseCase: GetLeagueScheduleUseCase, private readonly getLeagueAdminPermissionsUseCase: GetLeagueAdminPermissionsUseCase, @Inject(LOGGER_TOKEN) private readonly logger: Logger, ) {} async getAllLeaguesWithCapacity(): Promise { this.logger.debug('[LeagueService] Fetching all leagues with capacity.'); const presenter = new AllLeaguesWithCapacityPresenter(); await this.getAllLeaguesWithCapacityUseCase.execute(undefined, presenter); return presenter.getViewModel()!; } async getTotalLeagues(): Promise { this.logger.debug('[LeagueService] Fetching total leagues count.'); const presenter = new TotalLeaguesPresenter(); await this.getTotalLeaguesUseCase.execute({}, presenter); return presenter.getViewModel()!; } async getLeagueJoinRequests(leagueId: string): Promise { this.logger.debug(`[LeagueService] Fetching join requests for league: ${leagueId}.`); const presenter = new LeagueJoinRequestsPresenter(); await this.getLeagueJoinRequestsUseCase.execute({ leagueId }, presenter); return presenter.getViewModel()!.joinRequests; } async approveLeagueJoinRequest(input: ApproveJoinRequestInput): Promise { this.logger.debug('Approving join request:', input); const presenter = new ApproveLeagueJoinRequestPresenter(); await this.approveLeagueJoinRequestUseCase.execute({ leagueId: input.leagueId, requestId: input.requestId }, presenter); return presenter.getViewModel()!; } async rejectLeagueJoinRequest(input: RejectJoinRequestInput): Promise { this.logger.debug('Rejecting join request:', input); const presenter = new RejectLeagueJoinRequestPresenter(); await this.rejectLeagueJoinRequestUseCase.execute({ requestId: input.requestId }, presenter); return presenter.getViewModel()!; } async getLeagueAdminPermissions(query: GetLeagueAdminPermissionsInput): Promise { this.logger.debug('Getting league admin permissions', { query }); const presenter = new GetLeagueAdminPermissionsPresenter(); await this.getLeagueAdminPermissionsUseCase.execute( { leagueId: query.leagueId, performerDriverId: query.performerDriverId }, presenter ); return presenter.getViewModel()!; } async removeLeagueMember(input: RemoveLeagueMemberInput): Promise { this.logger.debug('Removing league member', { leagueId: input.leagueId, targetDriverId: input.targetDriverId }); const presenter = new RemoveLeagueMemberPresenter(); await this.removeLeagueMemberUseCase.execute({ leagueId: input.leagueId, targetDriverId: input.targetDriverId }, presenter); return presenter.getViewModel()!; } async updateLeagueMemberRole(input: UpdateLeagueMemberRoleInput): Promise { this.logger.debug('Updating league member role', { leagueId: input.leagueId, targetDriverId: input.targetDriverId, newRole: input.newRole }); const presenter = new UpdateLeagueMemberRolePresenter(); await this.updateLeagueMemberRoleUseCase.execute({ leagueId: input.leagueId, targetDriverId: input.targetDriverId, newRole: input.newRole }, presenter); return presenter.getViewModel()!; } async getLeagueOwnerSummary(query: GetLeagueOwnerSummaryQuery): Promise { this.logger.debug('Getting league owner summary:', query); const presenter = new GetLeagueOwnerSummaryPresenter(); await this.getLeagueOwnerSummaryUseCase.execute({ ownerId: query.ownerId }, presenter); return presenter.getViewModel()!.summary; } async getLeagueFullConfig(query: GetLeagueAdminConfigQuery): Promise { this.logger.debug('Getting league full config', { query }); const presenter = new LeagueConfigPresenter(); try { await this.getLeagueFullConfigUseCase.execute({ leagueId: query.leagueId }, presenter); return presenter.viewModel; } catch (error) { this.logger.error('Error getting league full config', error); return null; } } async getLeagueProtests(query: GetLeagueProtestsQuery): Promise { this.logger.debug('Getting league protests:', query); const presenter = new GetLeagueProtestsPresenter(); await this.getLeagueProtestsUseCase.execute({ leagueId: query.leagueId }, presenter); return presenter.getViewModel()!; } async getLeagueSeasons(query: GetLeagueSeasonsQuery): Promise { this.logger.debug('Getting league seasons:', query); const presenter = new GetLeagueSeasonsPresenter(); await this.getLeagueSeasonsUseCase.execute({ leagueId: query.leagueId }, presenter); return presenter.getViewModel()!.seasons; } async getLeagueMemberships(leagueId: string): Promise { this.logger.debug('Getting league memberships', { leagueId }); const presenter = new GetLeagueMembershipsPresenter(); await this.getLeagueMembershipsUseCase.execute({ leagueId }, presenter); return presenter.apiViewModel!; } async getLeagueStandings(leagueId: string): Promise { this.logger.debug('Getting league standings', { leagueId }); const presenter = new LeagueStandingsPresenter(); await this.getLeagueStandingsUseCase.execute({ leagueId }, presenter); return presenter.getViewModel()!; } async getLeagueSchedule(leagueId: string): Promise { this.logger.debug('Getting league schedule', { leagueId }); const presenter = new LeagueSchedulePresenter(); await this.getLeagueScheduleUseCase.execute({ leagueId }, presenter); return presenter.getViewModel()!; } async getLeagueStats(leagueId: string): Promise { this.logger.debug('Getting league stats', { leagueId }); const presenter = new LeagueStatsPresenter(); await this.getLeagueStatsUseCase.execute({ leagueId }, presenter); return presenter.getViewModel()!; } async getLeagueAdmin(leagueId: string): Promise { this.logger.debug('Getting league admin data', { leagueId }); // For now, we'll keep the orchestration in the service since it combines multiple use cases // TODO: Create a composite use case that handles all the admin data fetching const joinRequests = await this.getLeagueJoinRequests(leagueId); const config = await this.getLeagueFullConfig({ leagueId }); const protests = await this.getLeagueProtests({ leagueId }); const seasons = await this.getLeagueSeasons({ leagueId }); // Get owner summary - we need the ownerId, so we use a simple approach for now // In a full implementation, we'd have a use case that gets league basic info const ownerSummary = config ? await this.getLeagueOwnerSummary({ ownerId: 'placeholder', leagueId }) : null; return { joinRequests, ownerSummary, config: { form: config }, protests, seasons, }; } async createLeague(input: CreateLeagueInput): Promise { this.logger.debug('Creating league', { input }); const command = { name: input.name, description: input.description, ownerId: input.ownerId, visibility: 'unranked' as const, gameId: 'iracing', // Assume default maxDrivers: 32, // Default value enableDriverChampionship: true, enableTeamChampionship: false, enableNationsChampionship: false, enableTrophyChampionship: false, }; const result = await this.createLeagueWithSeasonAndScoringUseCase.execute(command); return { leagueId: result.leagueId, success: true, }; } }