import { Body, Controller, Get, Param, Post, Req, UseGuards } from '@nestjs/common';
import type { Request } from 'express';
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
import { AuthGuard } from '../common/auth.guard';
import { AuthenticatedUser } from './auth.types';
import { RefreshTokenDto } from './dto/refresh-token.dto';
import { LogoutDto } from './dto/logout.dto';
import { RequestPasswordResetDto } from './dto/request-password-reset.dto';
import { CompletePasswordResetDto } from './dto/complete-password-reset.dto';
import { TwoFactorCodeDto } from './dto/two-factor-code.dto';
import { VerifyTwoFactorLoginDto } from './dto/verify-two-factor-login.dto';

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

  constructor(authService: AuthService) {
    this.authService = authService;
  }

  @Post('login')
  signIn(@Req() request: Request, @Body() body: LoginDto) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    return this.authService.login(body.email, body.password, ipAddress);
  }

  @Post('refresh')
  refresh(@Req() request: Request, @Body() body: RefreshTokenDto) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    return this.authService.refresh(body.refreshToken, ipAddress);
  }

  @Post('logout')
  signOut(@Req() request: Request, @Body() body: LogoutDto) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    const authHeader = request.headers.authorization;
    const token =
      typeof authHeader === 'string' && authHeader.startsWith('Bearer ')
        ? authHeader.slice('Bearer '.length).trim()
        : undefined;
    return this.authService.logout({ accessToken: token, refreshToken: body.refreshToken, ipAddress });
  }

  @Post('forgot-password')
  forgotPassword(@Req() request: Request, @Body() body: RequestPasswordResetDto) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    return this.authService.requestPasswordReset(body.email, ipAddress);
  }

  @Get('password-reset/:token')
  getPasswordReset(@Param('token') token: string) {
    return this.authService.getPasswordResetToken(token);
  }

  @Post('password-reset/:token')
  completePasswordReset(
    @Req() request: Request,
    @Param('token') token: string,
    @Body() body: CompletePasswordResetDto,
  ) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    return this.authService.completePasswordReset(token, body.password, ipAddress);
  }

  @UseGuards(AuthGuard)
  @Get('me')
  getMe(@Req() request: Request & { user: AuthenticatedUser }) {
    return this.authService.me(request.user.sub);
  }

  @UseGuards(AuthGuard)
  @Get('session')
  getCurrentSession(@Req() request: Request & { user: AuthenticatedUser }) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    return this.authService.getCurrentSession(request.user, ipAddress);
  }

  @UseGuards(AuthGuard)
  @Get('2fa/status')
  getTwoFactorStatus(@Req() request: Request & { user: AuthenticatedUser }) {
    return this.authService.getTwoFactorStatus(request.user.sub);
  }

  @UseGuards(AuthGuard)
  @Post('2fa/setup/initiate')
  initiateTwoFactorSetup(@Req() request: Request & { user: AuthenticatedUser }) {
    return this.authService.initiateTwoFactorSetup(request.user.sub);
  }

  @UseGuards(AuthGuard)
  @Post('2fa/setup/confirm')
  confirmTwoFactorSetup(
    @Req() request: Request & { user: AuthenticatedUser },
    @Body() body: TwoFactorCodeDto,
  ) {
    return this.authService.confirmTwoFactorSetup(request.user.sub, body.code, request.ip);
  }

  @UseGuards(AuthGuard)
  @Post('2fa/disable')
  disableTwoFactor(
    @Req() request: Request & { user: AuthenticatedUser },
    @Body() body: TwoFactorCodeDto,
  ) {
    return this.authService.disableTwoFactor(request.user.sub, body.code, request.ip);
  }

  @UseGuards(AuthGuard)
  @Post('2fa/recovery-codes/regenerate')
  regenerateTwoFactorRecoveryCodes(
    @Req() request: Request & { user: AuthenticatedUser },
    @Body() body: TwoFactorCodeDto,
  ) {
    return this.authService.regenerateTwoFactorRecoveryCodes(request.user.sub, body.code, request.ip);
  }

  @Post('2fa/login/verify')
  verifyTwoFactorLogin(@Req() request: Request, @Body() body: VerifyTwoFactorLoginDto) {
    const forwarded = request.headers['x-forwarded-for'];
    const ipAddress = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : request.ip;
    return this.authService.verifyTwoFactorLogin(body.challengeToken, body.code, ipAddress);
  }
}
