import { NextResponse } from "next/server";
import { getRateLimitForScopes } from "./keys";
import { rateLimitCache, getCacheKey } from "./cache";
function checkRateLimit(identifier, limit = 1e3, windowMs = 6e4) {
  const now = Date.now();
  const cacheKey = getCacheKey("rate_limit", identifier);
  const current = rateLimitCache.get(cacheKey);
  if (!current || current.resetTime < now) {
    const resetTime = now + windowMs;
    const newEntry = { count: 1, resetTime };
    rateLimitCache.set(cacheKey, newEntry, windowMs);
    return {
      allowed: true,
      remaining: limit - 1,
      resetTime,
      limit
    };
  }
  if (current.count >= limit) {
    return {
      allowed: false,
      remaining: 0,
      resetTime: current.resetTime,
      limit
    };
  }
  current.count++;
  const ttl = current.resetTime - now;
  rateLimitCache.set(cacheKey, current, ttl);
  return {
    allowed: true,
    remaining: limit - current.count,
    resetTime: current.resetTime,
    limit
  };
}
function applyRateLimit(request, keyId, scopes) {
  const rateLimits = getRateLimitForScopes(scopes);
  const rateLimit = checkRateLimit(keyId, rateLimits.requests, rateLimits.windowMs);
  if (!rateLimit.allowed) {
    return NextResponse.json(
      {
        success: false,
        error: "Rate limit exceeded",
        message: "Too many requests. Please try again later.",
        code: "RATE_LIMIT_EXCEEDED",
        meta: {
          limit: rateLimit.limit,
          remaining: rateLimit.remaining,
          resetTime: new Date(rateLimit.resetTime).toISOString(),
          retryAfter: Math.ceil((rateLimit.resetTime - Date.now()) / 1e3)
        }
      },
      {
        status: 429,
        headers: {
          "X-RateLimit-Limit": rateLimit.limit.toString(),
          "X-RateLimit-Remaining": rateLimit.remaining.toString(),
          "X-RateLimit-Reset": rateLimit.resetTime.toString(),
          "Retry-After": Math.ceil((rateLimit.resetTime - Date.now()) / 1e3).toString()
        }
      }
    );
  }
  return null;
}
function addRateLimitHeaders(response, keyId, scopes) {
  const rateLimits = getRateLimitForScopes(scopes);
  const rateLimit = checkRateLimit(keyId, rateLimits.requests, rateLimits.windowMs);
  response.headers.set("X-RateLimit-Limit", rateLimit.limit.toString());
  response.headers.set("X-RateLimit-Remaining", Math.max(0, rateLimit.remaining).toString());
  response.headers.set("X-RateLimit-Reset", rateLimit.resetTime.toString());
  return response;
}
function withRateLimit(handler) {
  return async (request, ...args) => {
    try {
      const keyId = request.headers.get("x-api-key-id");
      const scopesHeader = request.headers.get("x-api-scopes");
      if (!keyId || !scopesHeader) {
        return handler(request, ...args);
      }
      const scopes = JSON.parse(scopesHeader);
      const rateLimitResponse = applyRateLimit(request, keyId, scopes);
      if (rateLimitResponse) {
        return rateLimitResponse;
      }
      const response = await handler(request, ...args);
      return addRateLimitHeaders(response, keyId, scopes);
    } catch (error) {
      console.error("Rate limiting error:", error);
      return handler(request, ...args);
    }
  };
}
function getRateLimitStats(keyId) {
  const cacheKey = getCacheKey("rate_limit", keyId);
  const current = rateLimitCache.get(cacheKey);
  if (!current) {
    return null;
  }
  return {
    currentUsage: current.count,
    resetTime: current.resetTime,
    isNearLimit: current.count > 800
    // 80% del límite por defecto
  };
}
function clearRateLimit(keyId) {
  const cacheKey = getCacheKey("rate_limit", keyId);
  rateLimitCache.delete(cacheKey);
}
function getAllRateLimitStats() {
  const cacheStats = rateLimitCache.getStats();
  return [{
    keyId: "cache_summary",
    count: cacheStats.active,
    resetTime: Date.now() + 6e4
    // Próximo cleanup
  }];
}
function getRateLimitCacheStats() {
  return rateLimitCache.getStats();
}
export {
  addRateLimitHeaders,
  applyRateLimit,
  checkRateLimit,
  clearRateLimit,
  getAllRateLimitStats,
  getRateLimitCacheStats,
  getRateLimitStats,
  withRateLimit
};
