/**
 * Federation Auth Controller
 *
 * API endpoints for federated OIDC authentication.
 * Issue #272: Rate limiting applied to prevent DoS attacks
 */

import { Controller, Post, Get, Delete, Body, Param, Req, UseGuards, Logger } from "@nestjs/common";
import { Throttle } from "@nestjs/throttler";
import { OIDCService } from "./oidc.service";
import { FederationAuditService } from "./audit.service";
import { AuthGuard } from "../auth/guards/auth.guard";
import type { AuthenticatedRequest } from "../common/types/user.types";
import type { FederatedIdentity, FederatedTokenValidation } from "./types/oidc.types";
import {
  InitiateFederatedAuthDto,
  LinkFederatedIdentityDto,
  ValidateFederatedTokenDto,
} from "./dto/federated-auth.dto";

@Controller("v1/federation/auth")
export class FederationAuthController {
  private readonly logger = new Logger(FederationAuthController.name);

  constructor(
    private readonly oidcService: OIDCService,
    private readonly auditService: FederationAuditService
  ) {}

  /**
   * Initiate federated authentication flow
   * Returns authorization URL to redirect user to
   * Rate limit: "medium" tier (20 req/min) - authenticated endpoint
   */
  @Post("initiate")
  @UseGuards(AuthGuard)
  @Throttle({ medium: { limit: 20, ttl: 60000 } })
  initiateAuth(
    @Req() req: AuthenticatedRequest,
    @Body() dto: InitiateFederatedAuthDto
  ): { authUrl: string; state: string } {
    if (!req.user) {
      throw new Error("User not authenticated");
    }

    this.logger.log(`User ${req.user.id} initiating federated auth with ${dto.remoteInstanceId}`);

    const authUrl = this.oidcService.generateAuthUrl(dto.remoteInstanceId, dto.redirectUrl);

    // Audit log
    this.auditService.logFederatedAuthInitiation(req.user.id, dto.remoteInstanceId);

    return {
      authUrl,
      state: dto.remoteInstanceId,
    };
  }

  /**
   * Link federated identity to local user
   * Rate limit: "medium" tier (20 req/min) - authenticated endpoint
   */
  @Post("link")
  @UseGuards(AuthGuard)
  @Throttle({ medium: { limit: 20, ttl: 60000 } })
  async linkIdentity(
    @Req() req: AuthenticatedRequest,
    @Body() dto: LinkFederatedIdentityDto
  ): Promise<FederatedIdentity> {
    if (!req.user) {
      throw new Error("User not authenticated");
    }

    this.logger.log(`User ${req.user.id} linking federated identity with ${dto.remoteInstanceId}`);

    const identity = await this.oidcService.linkFederatedIdentity(
      req.user.id,
      dto.remoteUserId,
      dto.remoteInstanceId,
      dto.oidcSubject,
      dto.email,
      dto.metadata
    );

    // Audit log
    this.auditService.logFederatedIdentityLinked(req.user.id, dto.remoteInstanceId);

    return identity;
  }

  /**
   * Get user's federated identities
   * Rate limit: "long" tier (200 req/hour) - read-only endpoint
   */
  @Get("identities")
  @UseGuards(AuthGuard)
  @Throttle({ long: { limit: 200, ttl: 3600000 } })
  async getIdentities(@Req() req: AuthenticatedRequest): Promise<FederatedIdentity[]> {
    if (!req.user) {
      throw new Error("User not authenticated");
    }

    return this.oidcService.getUserFederatedIdentities(req.user.id);
  }

  /**
   * Revoke a federated identity
   * Rate limit: "medium" tier (20 req/min) - authenticated endpoint
   */
  @Delete("identities/:instanceId")
  @UseGuards(AuthGuard)
  @Throttle({ medium: { limit: 20, ttl: 60000 } })
  async revokeIdentity(
    @Req() req: AuthenticatedRequest,
    @Param("instanceId") instanceId: string
  ): Promise<{ success: boolean }> {
    if (!req.user) {
      throw new Error("User not authenticated");
    }

    this.logger.log(`User ${req.user.id} revoking federated identity with ${instanceId}`);

    await this.oidcService.revokeFederatedIdentity(req.user.id, instanceId);

    // Audit log
    this.auditService.logFederatedIdentityRevoked(req.user.id, instanceId);

    return { success: true };
  }

  /**
   * Validate a federated token
   * Public endpoint (no auth required) - used by federated instances
   * Rate limit: "short" tier (3 req/sec) - CRITICAL DoS protection (Issue #272)
   */
  @Post("validate")
  @Throttle({ short: { limit: 3, ttl: 1000 } })
  async validateToken(@Body() dto: ValidateFederatedTokenDto): Promise<FederatedTokenValidation> {
    this.logger.debug(`Validating federated token from ${dto.instanceId}`);

    return this.oidcService.validateToken(dto.token, dto.instanceId);
  }
}
