/**
 * Simple in-memory rate limiter
 * For production with multiple servers, consider using Redis/Upstash
 */

interface RateLimitEntry {
  count: number;
  resetAt: number;
}

// Store rate limit data in memory
const rateLimitStore = new Map<string, RateLimitEntry>();

// Cleanup old entries every 5 minutes
setInterval(() => {
  const now = Date.now();
  const entries = Array.from(rateLimitStore.entries());
  for (const [key, entry] of entries) {
    if (entry.resetAt < now) {
      rateLimitStore.delete(key);
    }
  }
}, 5 * 60 * 1000);

export interface RateLimitConfig {
  /**
   * Maximum number of requests allowed in the window
   */
  maxRequests: number;

  /**
   * Time window in seconds
   */
  windowSeconds: number;

  /**
   * Unique identifier for this rate limiter (e.g., 'login', 'signup')
   */
  name: string;
}

export interface RateLimitResult {
  success: boolean;
  limit: number;
  remaining: number;
  reset: number;
}

/**
 * Check if a request should be rate limited
 *
 * @param identifier - Unique identifier for the client (e.g., IP address, email)
 * @param config - Rate limit configuration
 * @returns RateLimitResult
 */
export function rateLimit(
  identifier: string,
  config: RateLimitConfig
): RateLimitResult {
  const key = `${config.name}:${identifier}`;
  const now = Date.now();
  const windowMs = config.windowSeconds * 1000;

  let entry = rateLimitStore.get(key);

  // Create new entry if doesn't exist or expired
  if (!entry || entry.resetAt < now) {
    entry = {
      count: 0,
      resetAt: now + windowMs,
    };
    rateLimitStore.set(key, entry);
  }

  // Increment counter
  entry.count++;

  const remaining = Math.max(0, config.maxRequests - entry.count);
  const success = entry.count <= config.maxRequests;

  return {
    success,
    limit: config.maxRequests,
    remaining,
    reset: entry.resetAt,
  };
}

/**
 * Get client identifier from request (IP address)
 */
export function getClientIdentifier(request: Request): string {
  // Try to get real IP from headers (for proxies/load balancers)
  const forwardedFor = request.headers.get('x-forwarded-for');
  if (forwardedFor) {
    return forwardedFor.split(',')[0].trim();
  }

  const realIp = request.headers.get('x-real-ip');
  if (realIp) {
    return realIp;
  }

  // Fallback (this won't work well in production behind a proxy)
  return 'unknown';
}

/**
 * Predefined rate limit configurations
 */
export const RateLimits = {
  // Auth endpoints
  // Login: 5 attempts per 15 minutes
  LOGIN: {
    name: 'login',
    maxRequests: 5,
    windowSeconds: 15 * 60,
  },

  // Signup: 3 accounts per hour
  SIGNUP: {
    name: 'signup',
    maxRequests: 3,
    windowSeconds: 60 * 60,
  },

  // Password reset: 3 attempts per hour
  PASSWORD_RESET: {
    name: 'password-reset',
    maxRequests: 3,
    windowSeconds: 60 * 60,
  },

  // QR Code endpoints
  // Create QR: 20 per minute
  QR_CREATE: {
    name: 'qr-create',
    maxRequests: 20,
    windowSeconds: 60,
  },

  // Modify QR: 30 per minute
  QR_MODIFY: {
    name: 'qr-modify',
    maxRequests: 30,
    windowSeconds: 60,
  },

  // Delete all QRs: 3 per hour
  QR_DELETE_ALL: {
    name: 'qr-delete-all',
    maxRequests: 3,
    windowSeconds: 60 * 60,
  },

  // Bulk create: 3 per hour
  BULK_CREATE: {
    name: 'bulk-create',
    maxRequests: 3,
    windowSeconds: 60 * 60,
  },

  // User settings endpoints
  // Profile update: 10 per minute
  PROFILE_UPDATE: {
    name: 'profile-update',
    maxRequests: 10,
    windowSeconds: 60,
  },

  // Password change: 5 per hour
  PASSWORD_CHANGE: {
    name: 'password-change',
    maxRequests: 5,
    windowSeconds: 60 * 60,
  },

  // Account delete: 2 per day
  ACCOUNT_DELETE: {
    name: 'account-delete',
    maxRequests: 2,
    windowSeconds: 24 * 60 * 60,
  },

  // Analytics endpoints
  // Analytics summary: 30 per minute
  ANALYTICS: {
    name: 'analytics',
    maxRequests: 30,
    windowSeconds: 60,
  },

  // Stripe endpoints
  // Checkout session: 5 per minute
  STRIPE_CHECKOUT: {
    name: 'stripe-checkout',
    maxRequests: 5,
    windowSeconds: 60,
  },

  // Customer portal: 10 per minute
  STRIPE_PORTAL: {
    name: 'stripe-portal',
    maxRequests: 10,
    windowSeconds: 60,
  },

  // Cancel subscription: 3 per hour
  STRIPE_CANCEL: {
    name: 'stripe-cancel',
    maxRequests: 3,
    windowSeconds: 60 * 60,
  },

  // Newsletter endpoints
  // Newsletter subscribe: 5 per hour (prevent spam)
  NEWSLETTER_SUBSCRIBE: {
    name: 'newsletter-subscribe',
    maxRequests: 5,
    windowSeconds: 60 * 60,
  },

  // General API: 100 requests per minute
  API: {
    name: 'api',
    maxRequests: 100,
    windowSeconds: 60,
  },
};
