import {
  Controller,
  Post,
  Body,
  Res,
  Req,
  HttpCode,
  HttpStatus,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { Public } from '../../common/decorators/public.decorator';
import { CurrentUser, JwtPayload } from '../../common/decorators/current-user.decorator';
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
import { Enable2faDto } from './dto/enable-2fa.dto';
import { Disable2faDto } from './dto/disable-2fa.dto';

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

  /**
   * POST /api/v1/auth/login
   * Login mit E-Mail + Passwort (+ optionaler TOTP-Code).
   */
  @Post('login')
  @Public()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Login mit E-Mail und Passwort' })
  async login(
    @Body() dto: LoginDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    const result = await this.authService.login(dto);

    // 2FA erforderlich - kein Token setzen
    if (result.requiresTwoFactor) {
      return {
        requiresTwoFactor: true,
        message: 'Bitte 2FA-Code eingeben',
      };
    }

    // Refresh-Token als HttpOnly Cookie setzen (NICHT im localStorage!)
    // Regel: Kein localStorage fuer Tokens
    this.setRefreshTokenCookie(res, result.refreshToken!);

    return {
      accessToken: result.accessToken,
      user: result.user,
    };
  }

  /**
   * POST /api/v1/auth/refresh
   * Token-Refresh via HttpOnly Cookie.
   */
  @Post('refresh')
  @Public()
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Access-Token erneuern (Silent Refresh)' })
  async refresh(
    @Req() req: Request,
    @Res({ passthrough: true }) res: Response,
  ) {
    const refreshToken = req.cookies?.refresh_token as string | undefined;
    if (!refreshToken) {
      res.status(HttpStatus.UNAUTHORIZED).json({
        message: 'Kein Refresh-Token vorhanden',
      });
      return;
    }

    const tokens = await this.authService.refreshTokens(refreshToken);
    this.setRefreshTokenCookie(res, tokens.refreshToken);

    return {
      accessToken: tokens.accessToken,
    };
  }

  /**
   * POST /api/v1/auth/logout
   * Logout: Tokens invalidieren, Cookie loeschen.
   */
  @Post('logout')
  @HttpCode(HttpStatus.OK)
  @ApiBearerAuth('access-token')
  @ApiOperation({ summary: 'Logout und Token-Invalidierung' })
  async logout(
    @CurrentUser() user: JwtPayload,
    @Req() req: Request,
    @Res({ passthrough: true }) res: Response,
  ) {
    const refreshToken = req.cookies?.refresh_token as string | undefined;
    await this.authService.logout(user, refreshToken);

    // Refresh-Token Cookie loeschen
    const isProduction = process.env.NODE_ENV === 'production';
    res.clearCookie('refresh_token', {
      httpOnly: true,
      secure: isProduction,
      sameSite: isProduction ? 'strict' : 'lax',
      path: '/api/v1/auth',
    });

    return { message: 'Erfolgreich abgemeldet' };
  }

  /**
   * POST /api/v1/auth/2fa/setup
   * 2FA-Setup starten: Secret + QR-Code generieren.
   */
  @Post('2fa/setup')
  @HttpCode(HttpStatus.OK)
  @ApiBearerAuth('access-token')
  @ApiOperation({ summary: '2FA-Setup starten (QR-Code generieren)' })
  async setup2fa(@CurrentUser('sub') userId: string) {
    return this.authService.setup2fa(userId);
  }

  /**
   * POST /api/v1/auth/2fa/enable
   * 2FA aktivieren: TOTP-Code verifizieren.
   */
  @Post('2fa/enable')
  @HttpCode(HttpStatus.OK)
  @ApiBearerAuth('access-token')
  @ApiOperation({ summary: '2FA aktivieren (Code verifizieren)' })
  async enable2fa(
    @CurrentUser('sub') userId: string,
    @Body() dto: Enable2faDto,
  ) {
    await this.authService.enable2fa(userId, dto.totpCode);
    return { message: '2FA wurde erfolgreich aktiviert' };
  }

  /**
   * POST /api/v1/auth/2fa/disable
   * 2FA deaktivieren (mit Passwort-Bestaetigung).
   */
  @Post('2fa/disable')
  @HttpCode(HttpStatus.OK)
  @ApiBearerAuth('access-token')
  @ApiOperation({ summary: '2FA deaktivieren (Passwort erforderlich)' })
  async disable2fa(
    @CurrentUser('sub') userId: string,
    @Body() dto: Disable2faDto,
  ) {
    await this.authService.disable2fa(userId, dto.password);
    return { message: '2FA wurde erfolgreich deaktiviert' };
  }

  /**
   * Setzt das Refresh-Token als HttpOnly Cookie.
   * Secure + SameSite=Strict nur in Produktion (HTTPS).
   * In Development (HTTP) wird Secure deaktiviert und SameSite=Lax gesetzt.
   */
  private setRefreshTokenCookie(res: Response, refreshToken: string): void {
    const isProduction = process.env.NODE_ENV === 'production';
    res.cookie('refresh_token', refreshToken, {
      httpOnly: true,
      secure: isProduction,
      sameSite: isProduction ? 'strict' : 'lax',
      path: '/api/v1/auth',
      maxAge: 7 * 24 * 60 * 60 * 1000, // 7 Tage
    });
  }
}
