import {
  Controller,
  Get,
  Post,
  Body,
  HttpCode,
  HttpStatus,
  UseGuards,
  Request,
  UnauthorizedException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { Throttle } from '@nestjs/throttler';
import { AuthService, AuthTokens } from './auth.service';
import { TotpService } from './totp.service';
import { LoginDto } from './dto/login.dto';
import { RefreshTokenDto } from './dto/refresh-token.dto';
import { TotpVerifyDto, TotpValidateDto } from './dto/totp.dto';
import { JwtAuthGuard } from './guards/jwt-auth.guard';
import { verifySync } from 'otplib';

@ApiTags('Auth')
@Controller('auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private readonly totpService: TotpService,
  ) {}

  @Post('login')
  @Throttle({ default: { ttl: 60000, limit: 5 } })
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Login with phone and password' })
  @ApiResponse({ status: 200, description: 'Returns access and refresh tokens' })
  @ApiResponse({ status: 401, description: 'Invalid credentials' })
  async login(
    @Body() dto: LoginDto & { totpCode?: string },
  ): Promise<AuthTokens | { requireTotp: true; userId: string }> {
    const user = await this.authService.validateUser(dto.phone, dto.password);

    if (user.totpSecret) {
      if (!dto.totpCode) {
        return { requireTotp: true, userId: user.id };
      }

      const result = verifySync({
        token: dto.totpCode,
        secret: user.totpSecret,
      });

      if (!result.valid) {
        throw new UnauthorizedException('Invalid TOTP code');
      }
    }

    return this.authService.login(user);
  }

  @Post('refresh')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Refresh access token using refresh token' })
  @ApiResponse({ status: 200, description: 'Returns new access token' })
  @ApiResponse({ status: 401, description: 'Invalid or expired refresh token' })
  async refresh(
    @Body() dto: RefreshTokenDto,
  ): Promise<{ accessToken: string }> {
    return this.authService.refreshToken(dto.refreshToken);
  }

  @Get('profile')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Get current user profile' })
  @ApiResponse({ status: 200, description: 'Returns authenticated user profile' })
  async getProfile(@Request() req: any) {
    return this.authService.getProfile(req.user.sub);
  }

  @Post('totp/setup')
  @UseGuards(JwtAuthGuard)
  @HttpCode(HttpStatus.OK)
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Generate TOTP secret and QR code for 2FA setup' })
  async totpSetup(@Request() req: any) {
    return this.totpService.setup(req.user.sub);
  }

  @Post('totp/verify')
  @UseGuards(JwtAuthGuard)
  @HttpCode(HttpStatus.OK)
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Verify TOTP code and enable 2FA' })
  async totpVerify(@Request() req: any, @Body() dto: TotpVerifyDto) {
    await this.totpService.verify(req.user.sub, dto.token, dto.secret);
    return { enabled: true };
  }

  @Post('totp/validate')
  @Throttle({ default: { ttl: 60000, limit: 5 } })
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Validate TOTP code during login' })
  async totpValidate(@Body() dto: TotpValidateDto & { userId: string }) {
    const isValid = await this.totpService.validate(dto.userId, dto.token);
    if (!isValid) {
      throw new UnauthorizedException('Invalid TOTP code');
    }
    return { valid: true };
  }
}
