import { Controller, Get, Post, Patch, Body, Param } from '@nestjs/common'; import { ApiTags, ApiResponse, ApiOperation, ApiBody } from '@nestjs/swagger'; import { LeagueService } from './LeagueService'; import { AllLeaguesWithCapacityDTO } from './dtos/AllLeaguesWithCapacityDTO'; import { LeagueStatsDTO } from './dtos/LeagueStatsDTO'; import { LeagueJoinRequestDTO } from './dtos/LeagueJoinRequestDTO'; import { ApproveJoinRequestInputDTO } from './dtos/ApproveJoinRequestInputDTO'; import { ApproveJoinRequestOutputDTO } from './dtos/ApproveJoinRequestOutputDTO'; import { RejectJoinRequestInputDTO } from './dtos/RejectJoinRequestInputDTO'; import { RejectJoinRequestOutputDTO } from './dtos/RejectJoinRequestOutputDTO'; import { LeagueAdminPermissionsDTO } from './dtos/LeagueAdminPermissionsDTO'; import { RemoveLeagueMemberInputDTO } from './dtos/RemoveLeagueMemberInputDTO'; import { RemoveLeagueMemberOutputDTO } from './dtos/RemoveLeagueMemberOutputDTO'; import { UpdateLeagueMemberRoleInputDTO } from './dtos/UpdateLeagueMemberRoleInputDTO'; import { UpdateLeagueMemberRoleOutputDTO } from './dtos/UpdateLeagueMemberRoleOutputDTO'; import { LeagueOwnerSummaryDTO } from './dtos/LeagueOwnerSummaryDTO'; import { LeagueConfigFormModelDTO } from './dtos/LeagueConfigFormModelDTO'; import { LeagueAdminProtestsDTO } from './dtos/LeagueAdminProtestsDTO'; import { LeagueSeasonSummaryDTO } from './dtos/LeagueSeasonSummaryDTO'; import { LeagueMembershipsDTO } from './dtos/LeagueMembershipsDTO'; import { LeagueStandingsDTO } from './dtos/LeagueStandingsDTO'; import { LeagueScheduleDTO } from './dtos/LeagueScheduleDTO'; import { LeagueStatsDTO } from './dtos/LeagueStatsDTO'; import { LeagueAdminDTO } from './dtos/LeagueAdminDTO'; import { CreateLeagueInputDTO } from './dtos/CreateLeagueInputDTO'; import { CreateLeagueOutputDTO } from './dtos/CreateLeagueOutputDTO'; import { GetLeagueAdminPermissionsInputDTO } from './dtos/GetLeagueAdminPermissionsInputDTO'; import { GetLeagueJoinRequestsQueryDTO } from './dtos/GetLeagueJoinRequestsQueryDTO'; import { GetLeagueProtestsQueryDTO } from './dtos/GetLeagueProtestsQueryDTO'; import { GetLeagueSeasonsQueryDTO } from './dtos/GetLeagueSeasonsQueryDTO'; import { GetLeagueAdminConfigQueryDTO } from './dtos/GetLeagueAdminConfigQueryDTO'; import { GetLeagueOwnerSummaryQueryDTO } from './dtos/GetLeagueOwnerSummaryQueryDTO'; import { GetSeasonSponsorshipsOutputDTO } from './dtos/GetSeasonSponsorshipsOutputDTO'; import { GetLeagueRacesOutputDTO } from './dtos/GetLeagueRacesOutputDTO'; @ApiTags('leagues') @Controller('leagues') export class LeagueController { constructor(private readonly leagueService: LeagueService) {} @Get('all-with-capacity') @ApiOperation({ summary: 'Get all leagues with their capacity information' }) @ApiResponse({ status: 200, description: 'List of leagues with capacity', type: AllLeaguesWithCapacityDTO }) async getAllLeaguesWithCapacity(): Promise { return this.leagueService.getAllLeaguesWithCapacity(); } @Get('total-leagues') @ApiOperation({ summary: 'Get the total number of leagues' }) @ApiResponse({ status: 200, description: 'Total number of leagues', type: LeagueStatsDTO }) async getTotalLeagues(): Promise { return this.leagueService.getTotalLeagues(); } @Get(':leagueId/join-requests') @ApiOperation({ summary: 'Get all outstanding join requests for a league' }) @ApiResponse({ status: 200, description: 'List of join requests', type: [LeagueJoinRequestDTO] }) async getJoinRequests(@Param('leagueId') leagueId: string): Promise { // No specific query DTO needed for GET, leagueId from param return this.leagueService.getLeagueJoinRequests(leagueId); } @Post(':leagueId/join-requests/approve') @ApiOperation({ summary: 'Approve a league join request' }) @ApiBody({ type: ApproveJoinRequestInputDTO }) // Explicitly define body type for Swagger @ApiResponse({ status: 200, description: 'Join request approved', type: ApproveJoinRequestOutputDTO }) @ApiResponse({ status: 404, description: 'Join request not found' }) async approveJoinRequest( @Param('leagueId') leagueId: string, @Body() input: ApproveJoinRequestInputDTO, ): Promise { return this.leagueService.approveLeagueJoinRequest({ ...input, leagueId }); } @Post(':leagueId/join-requests/reject') @ApiOperation({ summary: 'Reject a league join request' }) @ApiBody({ type: RejectJoinRequestInputDTO }) @ApiResponse({ status: 200, description: 'Join request rejected', type: RejectJoinRequestOutputDTO }) @ApiResponse({ status: 404, description: 'Join request not found' }) async rejectJoinRequest( @Param('leagueId') leagueId: string, @Body() input: RejectJoinRequestInputDTO, ): Promise { return this.leagueService.rejectLeagueJoinRequest({ ...input, leagueId }); } @Get(':leagueId/permissions/:performerDriverId') @ApiOperation({ summary: 'Get league admin permissions for a performer' }) @ApiResponse({ status: 200, description: 'League admin permissions', type: LeagueAdminPermissionsDTO }) async getLeagueAdminPermissions( @Param('leagueId') leagueId: string, @Param('performerDriverId') performerDriverId: string, ): Promise { // No specific input DTO needed for Get, parameters from path return this.leagueService.getLeagueAdminPermissions({ leagueId, performerDriverId }); } @Patch(':leagueId/members/:targetDriverId/remove') @ApiOperation({ summary: 'Remove a member from the league' }) @ApiBody({ type: RemoveLeagueMemberInputDTO }) // Explicitly define body type for Swagger @ApiResponse({ status: 200, description: 'Member removed successfully', type: RemoveLeagueMemberOutputDTO }) @ApiResponse({ status: 400, description: 'Cannot remove member' }) @ApiResponse({ status: 404, description: 'Member not found' }) async removeLeagueMember( @Param('leagueId') leagueId: string, @Param('performerDriverId') performerDriverId: string, @Param('targetDriverId') targetDriverId: string, @Body() input: RemoveLeagueMemberInputDTO, // Body content for a patch often includes IDs ): Promise { return this.leagueService.removeLeagueMember({ leagueId, performerDriverId, targetDriverId }); } @Patch(':leagueId/members/:targetDriverId/role') @ApiOperation({ summary: "Update a member's role in the league" }) @ApiBody({ type: UpdateLeagueMemberRoleInputDTO }) // Explicitly define body type for Swagger @ApiResponse({ status: 200, description: 'Member role updated successfully', type: UpdateLeagueMemberRoleOutputDTO }) @ApiResponse({ status: 400, description: 'Cannot update role' }) @ApiResponse({ status: 404, description: 'Member not found' }) async updateLeagueMemberRole( @Param('leagueId') leagueId: string, @Param('performerDriverId') performerDriverId: string, @Param('targetDriverId') targetDriverId: string, @Body() input: UpdateLeagueMemberRoleInputDTO, // Body includes newRole, other for swagger ): Promise { return this.leagueService.updateLeagueMemberRole({ leagueId, performerDriverId, targetDriverId, newRole: input.newRole }); } @Get(':leagueId/owner-summary/:ownerId') @ApiOperation({ summary: 'Get owner summary for a league' }) @ApiResponse({ status: 200, description: 'League owner summary', type: LeagueOwnerSummaryDTO }) @ApiResponse({ status: 404, description: 'Owner or league not found' }) async getLeagueOwnerSummary( @Param('leagueId') leagueId: string, @Param('ownerId') ownerId: string, ): Promise { const query: GetLeagueOwnerSummaryQuery = { ownerId, leagueId }; return this.leagueService.getLeagueOwnerSummary(query); } @Get(':leagueId/config') @ApiOperation({ summary: 'Get league full configuration' }) @ApiResponse({ status: 200, description: 'League configuration form model', type: LeagueConfigFormModelDTO }) async getLeagueFullConfig( @Param('leagueId') leagueId: string, ): Promise { const query: GetLeagueAdminConfigQuery = { leagueId }; return this.leagueService.getLeagueFullConfig(query); } @Get(':leagueId/protests') @ApiOperation({ summary: 'Get protests for a league' }) @ApiResponse({ status: 200, description: 'List of protests for the league', type: LeagueAdminProtestsDTO }) async getLeagueProtests(@Param('leagueId') leagueId: string): Promise { const query: GetLeagueProtestsQuery = { leagueId }; return this.leagueService.getLeagueProtests(query); } @Get(':leagueId/protests/:protestId') @ApiOperation({ summary: 'Get a specific protest for a league' }) @ApiResponse({ status: 200, description: 'Protest details', type: LeagueAdminProtestsDTO }) async getLeagueProtest( @Param('leagueId') leagueId: string, @Param('protestId') protestId: string, ): Promise { const query: GetLeagueProtestsQuery = { leagueId }; const allProtests = await this.leagueService.getLeagueProtests(query); // Filter to only include the specific protest const protest = allProtests.protests.find(p => p.id === protestId); if (!protest) { throw new Error('Protest not found'); } // Find the race for this protest const race = allProtests.racesById[protest.raceId]; const protestingDriver = allProtests.driversById[protest.protestingDriverId]; const accusedDriver = allProtests.driversById[protest.accusedDriverId]; return { protests: [protest], racesById: race ? { [race.id]: race } : {}, driversById: { ...(protestingDriver ? { [protestingDriver.id]: protestingDriver } : {}), ...(accusedDriver ? { [accusedDriver.id]: accusedDriver } : {}), }, }; } @Get(':leagueId/seasons') @ApiOperation({ summary: 'Get seasons for a league' }) @ApiResponse({ status: 200, description: 'List of seasons for the league', type: [LeagueSeasonSummaryDTO] }) async getLeagueSeasons(@Param('leagueId') leagueId: string): Promise { const query: GetLeagueSeasonsQuery = { leagueId }; return this.leagueService.getLeagueSeasons(query); } @Get(':leagueId/memberships') @ApiOperation({ summary: 'Get league memberships' }) @ApiResponse({ status: 200, description: 'List of league members', type: LeagueMembershipsDTO }) async getLeagueMemberships(@Param('leagueId') leagueId: string): Promise { return this.leagueService.getLeagueMemberships(leagueId); } @Get(':leagueId/standings') @ApiOperation({ summary: 'Get league standings' }) @ApiResponse({ status: 200, description: 'League standings', type: LeagueStandingsDTO }) async getLeagueStandings(@Param('leagueId') leagueId: string): Promise { return this.leagueService.getLeagueStandings(leagueId); } @Get(':leagueId/schedule') @ApiOperation({ summary: 'Get league schedule' }) @ApiResponse({ status: 200, description: 'League schedule', type: LeagueScheduleDTO }) async getLeagueSchedule(@Param('leagueId') leagueId: string): Promise { return this.leagueService.getLeagueSchedule(leagueId); } @Get(':leagueId/stats') @ApiOperation({ summary: 'Get league stats' }) @ApiResponse({ status: 200, description: 'League stats', type: LeagueStatsDTO }) async getLeagueStats(@Param('leagueId') leagueId: string): Promise { return this.leagueService.getLeagueStats(leagueId); } @Get(':leagueId/admin') @ApiOperation({ summary: 'Get league admin data' }) @ApiResponse({ status: 200, description: 'League admin data', type: LeagueAdminDTO }) async getLeagueAdmin(@Param('leagueId') leagueId: string): Promise { return this.leagueService.getLeagueAdmin(leagueId); } @Post() @ApiOperation({ summary: 'Create a new league' }) @ApiBody({ type: CreateLeagueInputDTO }) @ApiResponse({ status: 201, description: 'League created successfully', type: CreateLeagueOutputDTO }) async createLeague(@Body() input: CreateLeagueInputDTO): Promise { return this.leagueService.createLeague(input); } @Get('scoring-presets') @ApiOperation({ summary: 'Get league scoring presets' }) @ApiResponse({ status: 200, description: 'List of scoring presets' }) async getLeagueScoringPresets() { return this.leagueService.listLeagueScoringPresets(); } @Get(':leagueId/scoring-config') @ApiOperation({ summary: 'Get league scoring config' }) @ApiResponse({ status: 200, description: 'League scoring config' }) async getLeagueScoringConfig(@Param('leagueId') leagueId: string) { return this.leagueService.getLeagueScoringConfig(leagueId); } @Post(':leagueId/join') @ApiOperation({ summary: 'Join a league' }) @ApiResponse({ status: 200, description: 'Joined league successfully' }) async joinLeague(@Param('leagueId') leagueId: string, @Body() body: { driverId: string }) { return this.leagueService.joinLeague(leagueId, body.driverId); } @Post(':leagueId/transfer-ownership') @ApiOperation({ summary: 'Transfer league ownership' }) @ApiResponse({ status: 200, description: 'Ownership transferred successfully' }) async transferLeagueOwnership(@Param('leagueId') leagueId: string, @Body() body: { currentOwnerId: string, newOwnerId: string }) { return this.leagueService.transferLeagueOwnership(leagueId, body.currentOwnerId, body.newOwnerId); } @Get('seasons/:seasonId/sponsorships') @ApiOperation({ summary: 'Get season sponsorships' }) @ApiResponse({ status: 200, description: 'Season sponsorships', type: GetSeasonSponsorshipsOutputDTO }) async getSeasonSponsorships(@Param('seasonId') seasonId: string): Promise { return this.leagueService.getSeasonSponsorships(seasonId); } @Get(':leagueId/races') @ApiOperation({ summary: 'Get league races' }) @ApiResponse({ status: 200, description: 'League races', type: GetLeagueRacesOutputDTO }) async getRaces(@Param('leagueId') leagueId: string): Promise { return this.leagueService.getRaces(leagueId); } }