import { Body, Controller, Get, Post, Query, Req, Res } from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import type { Request, Response } from 'express';

import { Public } from '../../common/auth/public.decorator';
import { LoginDto } from './dto/login.dto';
import { PasswordSetupTokenDto, SetPasswordDto } from './dto/password-setup.dto';
import { AuthService } from './auth.service';
import { clearAuthCookies, setAuthCookies } from './helpers/auth-cookie.helper';
import type { AuthRequestUser } from './interfaces/auth-request-user.interface';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Public()
  @Throttle({ default: { limit: 5, ttl: 60_000 } })
  @Post('login')
  async login(
    @Body() loginDto: LoginDto,
    @Res({ passthrough: true }) response: Response,
  ) {
    const result = await this.authService.login(loginDto);
    setAuthCookies(response, result.accessToken, result.refreshToken);
    return {
      user: result.user,
      redirectTo: result.redirectTo,
    };
  }

  @Public()
  @Throttle({ default: { limit: 10, ttl: 60_000 } })
  @Get('password-setup/validate')
  validatePasswordSetup(@Query() dto: PasswordSetupTokenDto) {
    return this.authService.validatePasswordSetup(dto.token);
  }

  @Public()
  @Throttle({ default: { limit: 5, ttl: 60_000 } })
  @Post('password-setup')
  setupPassword(@Body() dto: SetPasswordDto) {
    return this.authService.setupPassword(dto.token, dto.password);
  }

  @Public()
  @Throttle({ default: { limit: 10, ttl: 60_000 } })
  @Post('refresh')
  async refresh(
    @Req() request: Request,
    @Res({ passthrough: true }) response: Response,
  ) {
    const refreshToken = request.cookies?.iih_refresh_token as
      string | undefined;
    const result = await this.authService.refresh(refreshToken);
    setAuthCookies(response, result.accessToken, result.refreshToken);
    return {
      user: result.user,
      redirectTo: result.redirectTo,
    };
  }

  @Public()
  @Post('logout')
  async logout(
    @Req() request: Request,
    @Res({ passthrough: true }) response: Response,
  ) {
    const refreshToken = request.cookies?.iih_refresh_token as
      string | undefined;
    await this.authService.logout(refreshToken);
    clearAuthCookies(response);
    return { success: true };
  }

  @Get('me')
  async me(@Req() request: Request & { user: AuthRequestUser }) {
    return {
      user: request.user,
      redirectTo: this.authService.getRedirectPath(request.user.role),
    };
  }
}
