import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// Next.js 16 renamed middleware.ts -> proxy.ts (same request/response
// model, new name to make clear this runs at the network boundary, not as
// general app logic). See https://nextjs.org/docs/messages/middleware-to-proxy
//
// Two responsibilities live here, both because they need to run before
// routing on every request:
//   1. A per-request CSP nonce (can't be set from next.config headers()).
//   2. Rate limiting on /api/cron/* and /api/* in general, as a second
//      layer behind the CRON_SECRET bearer check in each route.

const RATE_LIMIT_WINDOW_MS = 60_000;
const RATE_LIMIT_MAX_REQUESTS = 30;

// In-memory fallback limiter. Correct for a single instance; NOT correct
// across multiple serverless regions/instances — configure
// UPSTASH_REDIS_REST_URL/TOKEN (see .env.example) for real distributed
// rate limiting in a multi-instance deployment.
const requestLog = new Map<string, number[]>();

function isRateLimited(key: string): boolean {
  const now = Date.now();
  const windowStart = now - RATE_LIMIT_WINDOW_MS;
  const timestamps = (requestLog.get(key) ?? []).filter((t) => t > windowStart);
  timestamps.push(now);
  requestLog.set(key, timestamps);

  // Bound memory growth in long-lived processes.
  if (requestLog.size > 10_000) {
    const oldestKey = requestLog.keys().next().value;
    if (oldestKey) requestLog.delete(oldestKey);
  }

  return timestamps.length > RATE_LIMIT_MAX_REQUESTS;
}

export async function proxy(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
  const { pathname } = request.nextUrl;

  if (pathname.startsWith('/api/')) {
    const ip = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown';
    if (isRateLimited(`${ip}:${pathname}`)) {
      return NextResponse.json({ error: 'Too many requests' }, { status: 429 });
    }
  }

  const cspHeader = [
    "default-src 'self'",
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`,
    "style-src 'self' 'unsafe-inline'",
    "img-src 'self' https://images.igdb.com https://media.rawg.io data:",
    "media-src 'self' https://www.youtube-nocookie.com",
    "frame-src https://www.youtube-nocookie.com",
    "connect-src 'self'",
    "font-src 'self'",
    "object-src 'none'",
    "base-uri 'self'",
    "frame-ancestors 'none'",
    'upgrade-insecure-requests',
  ].join('; ');

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set('Content-Security-Policy', cspHeader);
  return response;
}

export const config = {
  matcher: [
    // Run on everything except static assets and image optimization files.
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|webp|avif|ico)$).*)',
  ],
};
