import {
  Body,
  Controller,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  Req,
  UseGuards,
} from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import {
  ApiBearerAuth,
  ApiConflictResponse,
  ApiCreatedResponse,
  ApiOkResponse,
  ApiTags,
  ApiUnauthorizedResponse,
} from '@nestjs/swagger';
import { AuthService } from './auth.service';
import { AccountResponse } from './dto/account.response';
import { LoginDto, RefreshDto, TokensResponse } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import { JwtAuthGuard } from './jwt-auth.guard';
// `import type`: o tipo aparece em assinatura decorada e o emitDecoratorMetadata
// tentaria emiti-lo como valor em runtime.
import type { RequestAutenticado } from './jwt-auth.guard';
import { SessionService } from './session.service';

@ApiTags('Autenticação')
@Controller('auth')
export class AuthController {
  constructor(
    private readonly auth: AuthService,
    private readonly sessions: SessionService,
  ) {}

  @Post('register')
  @HttpCode(HttpStatus.CREATED)
  @ApiCreatedResponse({ type: AccountResponse })
  @ApiConflictResponse({ description: 'e-mail já cadastrado' })
  register(@Body() dto: RegisterDto): Promise<AccountResponse> {
    return this.auth.register(dto);
  }

  /**
   * Limite de tentativas por origem (AC-2 BE-3). Lido de `process.env` e não
   * do `ConfigService` porque decorator é avaliado na definição da classe e
   * não tem injeção — é o que permite o teste de rate limit ajustar o valor.
   */
  @Throttle({
    default: {
      limit: Number(process.env.THROTTLE_LOGIN_LIMIT ?? 5),
      ttl: 60_000,
    },
  })
  @Post('login')
  @HttpCode(HttpStatus.OK)
  @ApiOkResponse({ type: TokensResponse })
  @ApiUnauthorizedResponse({ description: 'credenciais inválidas' })
  login(@Body() dto: LoginDto): Promise<TokensResponse> {
    return this.auth.login(dto);
  }

  @Post('refresh')
  @HttpCode(HttpStatus.OK)
  @ApiOkResponse({ type: TokensResponse })
  refresh(@Body() dto: RefreshDto): Promise<TokensResponse> {
    return this.sessions.renovar(dto.refreshToken);
  }

  @Post('logout')
  @HttpCode(HttpStatus.NO_CONTENT)
  async logout(@Body() dto: RefreshDto): Promise<void> {
    await this.sessions.revogar(dto.refreshToken);
  }

  /** Prova que a sessão vale — usado pelo app no cold start (AC-3 FE-2). */
  @Get('me')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @ApiOkResponse({ type: AccountResponse })
  me(@Req() req: RequestAutenticado): Promise<AccountResponse> {
    return this.auth.contaPorId(req.conta.id);
  }
}
