import { Request } from 'express';
import rateLimit from 'express-rate-limit';
import jwt from 'jsonwebtoken';
import logger from '../utils/logger';

/**
 * Global safety-net rate limiter for all of /api. Protects against real abuse
 * (scraping, credential stuffing beyond what the auth-specific limiters already
 * catch, resource exhaustion) without punishing normal admin/teacher usage, where
 * a single UI action (e.g. editing a bot) fans out into several API calls.
 *
 * Keyed by user, not just IP: a logged-in admin's quota is tracked separately from
 * every other user, so one person's editing session — or several people behind the
 * same office/NAT IP — can't exhaust a shared per-IP budget and lock everyone else
 * out of login too (that's exactly what happened before: a single IP-wide counter
 * covered login *and* every other request).
 *
 * The JWT is decoded here only to read `userId` for this keying purpose — it is
 * NOT authentication and enforces nothing; real auth/authorization still happens
 * downstream via `authenticate` on each protected route. An invalid, expired, or
 * missing token just falls back to IP-based limiting, same as an anonymous request.
 */
function identifyForRateLimit(req: Request): string {
  try {
    const authHeader = req.headers.authorization;
    const token = authHeader?.startsWith('Bearer ')
      ? authHeader.substring(7)
      : req.cookies?.accessToken;

    if (token && process.env.JWT_SECRET) {
      const decoded = jwt.verify(token, process.env.JWT_SECRET) as { userId?: string };
      if (decoded?.userId) {
        return `user:${decoded.userId}`;
      }
    }
  } catch {
    // Invalid/expired token: fall through to IP-based limiting below.
  }

  return req.ip || 'unknown';
}

const windowMs = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000', 10); // 15 min
// Previous default (100/15min) counted every /api call — including the several
// requests a single UI action fans out into — against one shared budget, which a
// normal admin session (e.g. editing a handful of bots) could exhaust in minutes.
const maxRequests = parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '500', 10);

export const apiRateLimiter = rateLimit({
  windowMs,
  max: maxRequests,
  standardHeaders: true,
  legacyHeaders: false,
  keyGenerator: identifyForRateLimit,
  // Shape matches the rest of the API's { success, error: { message } } responses
  // (see errorHandler.ts) so the frontend's existing error parsing surfaces the real
  // message instead of falling back to Axios's generic "Request failed with status
  // code 429".
  handler: (req, res) => {
    logger.warn('🚫 Rate limit excedido en /api', {
      key: identifyForRateLimit(req),
      path: req.path,
      method: req.method,
      ip: req.ip,
      userAgent: req.get('User-Agent'),
    });

    res.status(429).json({
      success: false,
      error: {
        message: 'Too many requests. Please try again later.',
        retryAfter: Math.ceil(windowMs / 1000),
      },
    });
  },
});

export const apiRateLimiterConfig = { windowMs, maxRequests };
