import { Controller, Get, Post, Param, Delete, UseGuards, Session, HttpException, HttpStatus, Patch, Body, Sse, } from '@nestjs/common'; import { LobbyService } from '../services/lobby.service'; import { AuthGuard } from '../guards/auth.guard'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { GamePipe } from '../pipe/game.pipe'; import { Game } from '../schemas/game.schema'; import { Observable, fromEvent, map } from 'rxjs'; import { EventEmitter2 } from '@nestjs/event-emitter'; @ApiTags('lobby') @Controller('games') export class LobbyController { constructor( private readonly lobbyService: LobbyService, private eventEmitter: EventEmitter2, ) {} @Post() @ApiOperation({ summary: 'Create game' }) @ApiResponse({ status: 201, description: 'Game successfully created.', // type: ReadGameDto, }) @ApiResponse({ status: 400, description: 'You can only create one game at a time', }) @ApiResponse({ status: 403, description: 'Forbidden.' }) @UseGuards(AuthGuard) async create(@Session() session: Record) { const games = await this.lobbyService.findByOwner(session.user); if (games) { throw new HttpException( 'You can only create one game at a time', HttpStatus.BAD_REQUEST, ); } return await this.lobbyService.create(session.user); } @Get() @ApiOperation({ summary: 'List all games' }) findAll() { const games = this.lobbyService.findAll(); return games; } @Sse('/subscribe') subscribe(): Observable<{ data: string }> { return fromEvent(this.eventEmitter, 'sse.lobby').pipe( map((payload) => { return { data: JSON.stringify(payload), }; }), ); } @Get(':id') @ApiOperation({ summary: 'Get game information' }) async findOne(@Param('id') id: string, @Param('id', GamePipe) game: Game) { return game; // return new ReadGameDto(game); } @Delete(':id') @ApiOperation({ summary: 'Delete game' }) @UseGuards(AuthGuard) async remove( @Param('id') id: string, @Session() session: Record, @Param('id', GamePipe) game: Game, ) { if (game.owner.userId == session.user.userId) { throw new HttpException( 'You can only delete games you own', HttpStatus.FORBIDDEN, ); } await this.lobbyService.remove(game); } @Post(':id/join') @ApiOperation({ summary: 'Join game' }) @UseGuards(AuthGuard) async join( @Param('id') id: string, @Session() session: Record, @Param('id', GamePipe) game: Game, ) { if (game.started) { throw new HttpException('Game already started', HttpStatus.BAD_REQUEST); } if (game.players.some((p) => p.user.userId == session.user.userId)) { throw new HttpException( 'You are already in this game', HttpStatus.BAD_REQUEST, ); } return await this.lobbyService.joinGame(game, session.user); } @Post(':id/leave') @ApiOperation({ summary: "Leave a game that hasn't already started" }) @UseGuards(AuthGuard) async leave( @Param('id') id: string, @Session() session: Record, @Param('id', GamePipe) game: Game, ) { if (game.started) { throw new HttpException('Game already started', HttpStatus.BAD_REQUEST); } return await this.lobbyService.leaveGame(game, session.user); } }