import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  Patch,
  Post,
  Req,
  UseGuards,
} from '@nestjs/common';
import {
  ApiBearerAuth,
  ApiConflictResponse,
  ApiCreatedResponse,
  ApiOkResponse,
  ApiServiceUnavailableResponse,
  ApiTags,
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import type { RequestAutenticado } from '../auth/jwt-auth.guard';
import { ConviteResponse, EntrarDto, EntrarResponse } from './dto/convite.dto';
import { CriarPoolDto, PoolResponse } from './dto/criar-pool.dto';
import { RegrasDto, RegrasResponse } from './dto/regras.dto';
import { ConvitesService } from './convites.service';
import { PoolsService } from './pools.service';
import { RegrasService } from './regras.service';

@ApiTags('Bolões')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Controller('pools')
export class PoolsController {
  constructor(
    private readonly pools: PoolsService,
    private readonly regras: RegrasService,
    private readonly convites: ConvitesService,
  ) {}

  /** Bolões ativos de quem está autenticado. */
  @Get()
  @ApiOkResponse({ description: 'bolões do participante' })
  meus(@Req() req: RequestAutenticado) {
    return this.pools.meusBoloes(req.conta.id);
  }

  @Get('competitions')
  @ApiOkResponse({ description: 'campeonatos disponíveis' })
  @ApiServiceUnavailableResponse({ description: 'fonte de dados indisponível' })
  competicoes() {
    return this.pools.competicoes();
  }

  @Post()
  @ApiCreatedResponse({ type: PoolResponse })
  @ApiServiceUnavailableResponse({
    description: 'fonte indisponível — nenhum bolão é criado',
  })
  criar(
    @Body() dto: CriarPoolDto,
    @Req() req: RequestAutenticado,
  ): Promise<PoolResponse> {
    return this.pools.criar(dto, req.conta.id);
  }

  /** Visível a qualquer participante — o competitivo lê antes de palpitar. */
  @Get(':id/rules')
  @ApiOkResponse({ type: RegrasResponse })
  lerRegras(
    @Param('id') id: string,
    @Req() req: RequestAutenticado,
  ): Promise<RegrasResponse> {
    return this.regras.ler(id, req.conta.id);
  }

  @Patch(':id/rules')
  @ApiOkResponse({ type: RegrasResponse })
  @ApiConflictResponse({ description: 'regras travadas pelo primeiro palpite' })
  alterarRegras(
    @Param('id') id: string,
    @Body() dto: RegrasDto,
    @Req() req: RequestAutenticado,
  ): Promise<RegrasResponse> {
    return this.regras.alterar(id, req.conta.id, dto);
  }

  /** Gera o convite e **revoga o anterior**: o link antigo para na hora. */
  @Post(':id/invite')
  @ApiCreatedResponse({ type: ConviteResponse })
  gerarConvite(
    @Param('id') id: string,
    @Req() req: RequestAutenticado,
  ): Promise<ConviteResponse> {
    return this.convites.gerar(id, req.conta.id);
  }

  @Delete(':id/invite')
  @HttpCode(HttpStatus.NO_CONTENT)
  async invalidarConvite(
    @Param('id') id: string,
    @Req() req: RequestAutenticado,
  ): Promise<void> {
    await this.convites.invalidar(id, req.conta.id);
  }

  /**
   * Entrada pelo convite. Fora de `:id` de propósito: quem abre o link ainda
   * não sabe em que bolão vai entrar — é o token que diz.
   */
  @Post('join')
  @HttpCode(HttpStatus.OK)
  @ApiOkResponse({ type: EntrarResponse })
  entrar(
    @Body() dto: EntrarDto,
    @Req() req: RequestAutenticado,
  ): Promise<EntrarResponse> {
    return this.convites.entrar(dto.token, req.conta.id);
  }
}
