/**
 * Entra VerifiedID API rate limiting
 * Specific rate limits for Entra VerifiedID endpoints to prevent API quota exhaustion
 */

import { FastifyInstance, FastifyRequest } from 'fastify';
import fastifyRateLimit from '@fastify/rate-limit';
import { getEnv } from './env';

export interface EntraRateLimitConfig {
  issuance?: {
    max: number;
    timeWindow: string | number;
  };
  verification?: {
    max: number;
    timeWindow: string | number;
  };
  statusCheck?: {
    max: number;
    timeWindow: string | number;
  };
  global?: {
    max: number;
    timeWindow: string | number;
  };
}

/**
 * Register Entra VerifiedID-specific rate limiting
 */
export async function registerEntraRateLimit(
  server: FastifyInstance,
  config?: EntraRateLimitConfig
): Promise<void> {
  const env = getEnv();

  // Default configuration - conservative limits to avoid API quota issues
  const defaultConfig: Required<EntraRateLimitConfig> = {
    issuance: {
      max: parseInt(env.ENTRA_RATE_LIMIT_ISSUANCE || '10', 10),
      timeWindow: '1 minute',
    },
    verification: {
      max: parseInt(env.ENTRA_RATE_LIMIT_VERIFICATION || '20', 10),
      timeWindow: '1 minute',
    },
    statusCheck: {
      max: parseInt(env.ENTRA_RATE_LIMIT_STATUS_CHECK || '30', 10),
      timeWindow: '1 minute',
    },
    global: {
      max: parseInt(env.ENTRA_RATE_LIMIT_GLOBAL || '50', 10),
      timeWindow: '1 minute',
    },
  };

  const finalConfig = { ...defaultConfig, ...config };

  // Global Entra API rate limit
  await server.register(fastifyRateLimit, {
    max: finalConfig.global.max,
    timeWindow: finalConfig.global.timeWindow,
    keyGenerator: (request: FastifyRequest) => {
      // Rate limit by IP for Entra endpoints
      return `entra:global:${request.ip}`;
    },
    errorResponseBuilder: (_request, context) => {
      return {
        error: {
          code: 'ENTRA_RATE_LIMIT_EXCEEDED',
          message: `Entra API rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
        },
      };
    },
    skipOnError: false,
  });

  // Issuance-specific rate limit
  await server.register(fastifyRateLimit, {
    max: finalConfig.issuance.max,
    timeWindow: finalConfig.issuance.timeWindow,
    keyGenerator: (request: FastifyRequest) => {
      const userId = (request as any).user?.id || 'anonymous';
      return `entra:issuance:${userId}:${request.ip}`;
    },
    errorResponseBuilder: (_request, context) => {
      return {
        error: {
          code: 'ENTRA_ISSUANCE_RATE_LIMIT_EXCEEDED',
          message: `Entra issuance rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
        },
      };
    },
    skipOnError: false,
  });

  // Verification-specific rate limit
  await server.register(fastifyRateLimit, {
    max: finalConfig.verification.max,
    timeWindow: finalConfig.verification.timeWindow,
    keyGenerator: (request: FastifyRequest) => {
      return `entra:verification:${request.ip}`;
    },
    errorResponseBuilder: (_request, context) => {
      return {
        error: {
          code: 'ENTRA_VERIFICATION_RATE_LIMIT_EXCEEDED',
          message: `Entra verification rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
        },
      };
    },
    skipOnError: false,
  });

  // Status check-specific rate limit
  await server.register(fastifyRateLimit, {
    max: finalConfig.statusCheck.max,
    timeWindow: finalConfig.statusCheck.timeWindow,
    keyGenerator: (request: FastifyRequest) => {
      const requestId = (request.params as any)?.requestId || (request.query as any)?.requestId || 'unknown';
      return `entra:status:${requestId}`;
    },
    errorResponseBuilder: (_request, context) => {
      return {
        error: {
          code: 'ENTRA_STATUS_CHECK_RATE_LIMIT_EXCEEDED',
          message: `Entra status check rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
        },
      };
    },
    skipOnError: false,
  });
}

/**
 * Create Entra rate limit plugin
 */
export function createEntraRateLimitPlugin(config?: EntraRateLimitConfig) {
  return async function (server: FastifyInstance) {
    await registerEntraRateLimit(server, config);
  };
}

