import { jsonError } from './http.js';

export interface RateLimiter {
  limit(options: { key: string }): Promise<{ success: boolean }>;
}

export interface StorefrontLimiterEnv {
  STOREFRONT_LOGIN_LIMITER?: RateLimiter;
  CHECKOUT_LIMITER?: RateLimiter;
  ADMIN_LOGIN_LIMITER?: RateLimiter;
  ADMIN_API_LIMITER?: RateLimiter;
  INSTALL_LIMITER?: RateLimiter;
}

const ADMIN_PREFIX = '/api/admin/';
/** No route exists at this path — admin users sign in via `/api/auth/login` (STOREFRONT_LOGIN_LIMITER). */
const ADMIN_LOGIN_PATH = '/api/admin/session';
const AUTH_PREFIX = '/api/auth/';
const CHECKOUT_PREFIX = '/api/checkout/';
const INSTALL_PATH = '/api/install';

function rateLimitedResponse(): Response {
  const response = jsonError(429, 'rate_limited', 'Too many requests. Please retry shortly.');
  response.headers.set('Retry-After', '60');
  return response;
}

/**
 * Edge rate limits for storefront login, checkout, and admin APIs.
 * Endpoints where misconfiguration could grant unintended access (admin, install) fail-closed
 * (503) when their binding is absent; buyer checkout endpoints fail-open.
 */
export async function enforceStorefrontRateLimit(
  env: StorefrontLimiterEnv,
  request: Request,
): Promise<Response | null> {
  const { pathname } = new URL(request.url);
  const method = request.method;
  const ip = request.headers.get('CF-Connecting-IP') ?? 'unknown';

  if (pathname.startsWith(ADMIN_PREFIX)) {
    const normalizedPath = pathname.endsWith('/') && pathname.length > 1 ? pathname.slice(0, -1) : pathname;
    const isLogin = normalizedPath === ADMIN_LOGIN_PATH && method === 'POST';
    const limiter = isLogin ? env.ADMIN_LOGIN_LIMITER : env.ADMIN_API_LIMITER;
    if (!limiter) {
      return jsonError(503, 'service_unavailable', 'Service temporarily unavailable.');
    }

    const key = `${isLogin ? 'admin-login' : 'admin-api'}:${ip}`;
    const { success } = await limiter.limit({ key });
    if (success) return null;
    return rateLimitedResponse();
  }

  if (pathname.startsWith(AUTH_PREFIX) && method === 'POST') {
    const limiter = env.STOREFRONT_LOGIN_LIMITER;
    if (!limiter) return jsonError(503, 'service_unavailable', 'Service temporarily unavailable.');

    const { success } = await limiter.limit({ key: `storefront-login:${ip}` });
    if (success) return null;
    return rateLimitedResponse();
  }

  if (pathname.startsWith(CHECKOUT_PREFIX) && method === 'POST') {
    // Webhook is HMAC-gated by ingestWebhook — bypass the buyer per-IP limiter so
    // Stripe burst deliveries are not 429'd.
    if (pathname === `${CHECKOUT_PREFIX}webhook`) return null;

    const limiter = env.CHECKOUT_LIMITER;
    if (!limiter) return null;

    const { success } = await limiter.limit({ key: `checkout:${ip}` });
    if (success) return null;
    return rateLimitedResponse();
  }

  if (pathname === INSTALL_PATH && method === 'POST') {
    const limiter = env.INSTALL_LIMITER;
    if (!limiter) return jsonError(503, 'service_unavailable', 'Service temporarily unavailable.');

    const { success } = await limiter.limit({ key: `install:${ip}` });
    if (success) return null;
    return rateLimitedResponse();
  }

  return null;
}
