import {
  Controller,
  Get,
  Query,
  Req,
  Res,
  UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { Throttle } from '@nestjs/throttler';
import { type Request, type Response } from 'express';
import { UnauthorizedException } from '@modules/shared';
import { type TokenPair } from '../../infrastructure/services/token.service';
import { ZaloOAuthStrategy } from '../../infrastructure/strategies/zalo-oauth.strategy';
import { GoogleOAuthGuard } from '../guards/google-oauth.guard';

const IS_PRODUCTION = process.env['NODE_ENV'] === 'production';
const ACCESS_TOKEN_MAX_AGE = 15 * 60 * 1000;
const REFRESH_TOKEN_MAX_AGE = 30 * 24 * 60 * 60 * 1000;
const AUTH_COOKIE_MAX_AGE = 30 * 24 * 60 * 60 * 1000;

const FRONTEND_URL = process.env['FRONTEND_URL'] ?? 'http://localhost:3000';

function setAuthCookies(res: Response, tokens: TokenPair): void {
  res.cookie('access_token', tokens.accessToken, {
    httpOnly: true,
    secure: IS_PRODUCTION,
    sameSite: 'strict',
    path: '/',
    maxAge: ACCESS_TOKEN_MAX_AGE,
  });
  res.cookie('refresh_token', tokens.refreshToken, {
    httpOnly: true,
    secure: IS_PRODUCTION,
    sameSite: 'strict',
    path: '/auth',
    maxAge: REFRESH_TOKEN_MAX_AGE,
  });
  res.cookie('goodgo_authenticated', '1', {
    httpOnly: false,
    secure: IS_PRODUCTION,
    sameSite: 'lax',
    path: '/',
    maxAge: AUTH_COOKIE_MAX_AGE,
  });
}

@ApiTags('auth')
@Controller('auth')
export class OAuthController {
  constructor(private readonly zaloStrategy: ZaloOAuthStrategy) {}

  // ─── Google OAuth ──────────────────────────────────────────────────

  @Get('google')
  @UseGuards(GoogleOAuthGuard)
  @ApiOperation({ summary: 'Initiate Google OAuth2 login' })
  @ApiResponse({ status: 302, description: 'Redirect to Google consent screen' })
  googleLogin(): void {
    // Guard handles redirect to Google
  }

  @Throttle({ default: { ttl: 3_600_000, limit: 10 } })
  @Get('google/callback')
  @UseGuards(GoogleOAuthGuard)
  @ApiOperation({ summary: 'Google OAuth2 callback' })
  @ApiResponse({ status: 302, description: 'Redirect to frontend with auth cookies' })
  async googleCallback(
    @Req() req: Request,
    @Res() res: Response,
  ): Promise<void> {
    const tokens = req.user as TokenPair | undefined;
    if (!tokens?.accessToken) {
      throw new UnauthorizedException('Google authentication failed');
    }

    setAuthCookies(res, tokens);
    res.redirect(`${FRONTEND_URL}/auth/callback?provider=google`);
  }

  // ─── Zalo OAuth ────────────────────────────────────────────────────

  @Get('zalo')
  @ApiOperation({ summary: 'Initiate Zalo OAuth2 login' })
  @ApiResponse({ status: 302, description: 'Redirect to Zalo consent screen' })
  zaloLogin(@Res() res: Response): void {
    const authUrl = this.zaloStrategy.getAuthorizationUrl();
    res.redirect(authUrl);
  }

  @Throttle({ default: { ttl: 3_600_000, limit: 10 } })
  @Get('zalo/callback')
  @ApiOperation({ summary: 'Zalo OAuth2 callback' })
  @ApiResponse({ status: 302, description: 'Redirect to frontend with auth cookies' })
  async zaloCallback(
    @Query('code') code: string,
    @Query('code_verifier') codeVerifier: string | undefined,
    @Res() res: Response,
  ): Promise<void> {
    if (!code) {
      throw new UnauthorizedException('Zalo authorization code missing');
    }

    try {
      const result = await this.zaloStrategy.handleCallback(code, codeVerifier);
      setAuthCookies(res, result.tokens);
      res.redirect(`${FRONTEND_URL}/auth/callback?provider=zalo`);
    } catch {
      res.redirect(`${FRONTEND_URL}/auth/callback?error=zalo_auth_failed`);
    }
  }
}
