const logger = require('../utils/logger');

// Almacenar IPs sospechosas en memoria (en producción usar Redis)
const suspiciousIPs = new Map();
const blockedIPs = new Set();

// Configuración
const config = {
  maxRequestsPerSecond: 10,
  maxRequestsPerMinute: 100,
  blockDuration: 15 * 60 * 1000, // 15 minutos
  suspiciousThreshold: 50, // requests por segundo para marcar como sospechoso
  autoBlockThreshold: 100, // requests por segundo para bloqueo automático
};

// Limpiar datos antiguos cada 5 minutos
setInterval(() => {
  const now = Date.now();
  
  // Limpiar IPs sospechosas
  for (const [ip, data] of suspiciousIPs.entries()) {
    if (now - data.lastRequest > 5 * 60 * 1000) {
      suspiciousIPs.delete(ip);
    }
  }

  // Desbloquear IPs
  for (const ip of blockedIPs) {
    const data = suspiciousIPs.get(ip);
    if (data && now - data.blockedAt > config.blockDuration) {
      blockedIPs.delete(ip);
      suspiciousIPs.delete(ip);
      logger.info(`IP desbloqueada: ${ip}`);
    }
  }
}, 5 * 60 * 1000);

// Middleware principal de protección DDoS
const ddosProtection = (req, res, next) => {
  const ip = req.ip || req.connection.remoteAddress;
  const now = Date.now();

  // Verificar si la IP está bloqueada
  if (blockedIPs.has(ip)) {
    logger.security(`Request bloqueada de IP bloqueada: ${ip}`, {
      url: req.originalUrl,
      method: req.method,
    });

    return res.status(403).json({
      success: false,
      message: 'Su IP ha sido bloqueada temporalmente debido a actividad sospechosa',
    });
  }

  // Obtener o crear datos de la IP
  let ipData = suspiciousIPs.get(ip);
  
  if (!ipData) {
    ipData = {
      requestsPerSecond: [],
      requestsPerMinute: [],
      totalRequests: 0,
      lastRequest: now,
      firstRequest: now,
    };
    suspiciousIPs.set(ip, ipData);
  }

  // Actualizar contadores
  ipData.totalRequests++;
  ipData.lastRequest = now;

  // Limpiar requests antiguos (más de 1 segundo)
  ipData.requestsPerSecond = ipData.requestsPerSecond.filter(
    timestamp => now - timestamp < 1000
  );
  ipData.requestsPerSecond.push(now);

  // Limpiar requests antiguos (más de 1 minuto)
  ipData.requestsPerMinute = ipData.requestsPerMinute.filter(
    timestamp => now - timestamp < 60000
  );
  ipData.requestsPerMinute.push(now);

  // Verificar límites
  const requestsPerSecond = ipData.requestsPerSecond.length;
  const requestsPerMinute = ipData.requestsPerMinute.length;

  // Bloqueo automático por tráfico extremo
  if (requestsPerSecond > config.autoBlockThreshold) {
    blockedIPs.add(ip);
    ipData.blockedAt = now;
    
    logger.security(`IP bloqueada automáticamente por DDoS: ${ip}`, {
      requestsPerSecond,
      requestsPerMinute,
      totalRequests: ipData.totalRequests,
    });

    return res.status(429).json({
      success: false,
      message: 'Demasiadas peticiones. Su IP ha sido bloqueada temporalmente.',
    });
  }

  // Advertencia por tráfico sospechoso
  if (requestsPerSecond > config.suspiciousThreshold) {
    logger.warn(`Tráfico sospechoso detectado de IP: ${ip}`, {
      requestsPerSecond,
      requestsPerMinute,
      url: req.originalUrl,
    });
  }

  // Límite por segundo
  if (requestsPerSecond > config.maxRequestsPerSecond) {
    logger.warn(`Límite por segundo excedido para IP: ${ip}`, {
      requestsPerSecond,
      url: req.originalUrl,
    });

    return res.status(429).json({
      success: false,
      message: 'Demasiadas peticiones por segundo. Por favor, reduzca la velocidad.',
    });
  }

  // Límite por minuto
  if (requestsPerMinute > config.maxRequestsPerMinute) {
    logger.warn(`Límite por minuto excedido para IP: ${ip}`, {
      requestsPerMinute,
      url: req.originalUrl,
    });

    return res.status(429).json({
      success: false,
      message: 'Demasiadas peticiones por minuto. Por favor, espere un momento.',
    });
  }

  next();
};

// Middleware para detectar patrones de ataque
const detectAttackPatterns = (req, res, next) => {
  const ip = req.ip || req.connection.remoteAddress || req.socket.remoteAddress;
  const userAgent = req.get('user-agent') || '';
  const url = req.originalUrl || req.url;

  // 1. Bots maliciosos conocidos (esto sí lo dejamos tal cual)
  const maliciousBots = ['masscan', 'nmap', 'nikto', 'sqlmap', 'acunetix', 'nessus', 'openvas', 'zmap'];
  if (maliciousBots.some(bot => userAgent.toLowerCase().includes(bot))) {
    logger.security(`Bot malicioso detectado: ${ip}`, { userAgent, url });
    blockedIPs.add(ip);
    return res.status(403).json({
      success: false,
      message: 'Acceso denegado',
    });
  }

  // 2. SOLO aplicar filtro de escaneo a rutas que NO empiecen con /api/
  // Esto es clave: tus rutas reales de API nunca serán bloqueadas
  if (url.startsWith('/api/')) {
    return next();
  }

  // 3. Ahora sí, fuera de /api/ buscamos patrones realmente maliciosos
  const scanPatterns = [
    /(^|\/)\.(env|git|svn|hg|bzr|htaccess|htpasswd|DS_Store)/i,
    /(^|\/)(admin|cpanel|phpmyadmin|webmail|wp-admin|wp-login|\.git|\.env)/i,
    /\.(php|php\d|phtml|asp|aspx|jsp|jspx|cfm|cgi|pl|py|sh|exe|bat)(\?|#|$)/i,
    /(union.*select|select.*from.*information_schema|pg_catalog|mysql\.user)/i,
    /(eval|exec|system|passthru|popen|shell_exec|base64_decode)/i,
  ];

  if (scanPatterns.some(pattern => pattern.test(url))) {
    logger.security(`Intento de escaneo detectado: ${ip}`, { url, userAgent });
    return res.status(404).json({
      success: false,
      message: 'No encontrado',
    });
  }
  next();
};

// Middleware para limitar tamaño de requests
const requestSizeLimit = (maxSize = 10 * 1024 * 1024) => { // 10MB por defecto
  return (req, res, next) => {
    const contentLength = parseInt(req.get('content-length') || '0');

    if (contentLength > maxSize) {
      logger.security(`Request demasiado grande rechazada: ${req.ip}`, {
        contentLength,
        maxSize,
        url: req.originalUrl,
      });

      return res.status(413).json({
        success: false,
        message: 'Payload demasiado grande',
      });
    }

    next();
  };
};

// Middleware para detectar Slowloris attacks
const slowlorisProtection = (req, res, next) => {
  const timeout = 30000; // 30 segundos

  const timer = setTimeout(() => {
    logger.security(`Posible ataque Slowloris detectado: ${req.ip}`, {
      url: req.originalUrl,
      method: req.method,
    });

    req.destroy();
  }, timeout);

  res.on('finish', () => {
    clearTimeout(timer);
  });

  next();
};

// Función para obtener estadísticas
const getStats = () => {
  return {
    suspiciousIPs: suspiciousIPs.size,
    blockedIPs: blockedIPs.size,
    topIPs: Array.from(suspiciousIPs.entries())
      .sort((a, b) => b[1].totalRequests - a[1].totalRequests)
      .slice(0, 10)
      .map(([ip, data]) => ({
        ip,
        totalRequests: data.totalRequests,
        requestsPerSecond: data.requestsPerSecond.length,
        requestsPerMinute: data.requestsPerMinute.length,
      })),
  };
};

// Función para desbloquear IP manualmente
const unblockIP = (ip) => {
  if (blockedIPs.has(ip)) {
    blockedIPs.delete(ip);
    suspiciousIPs.delete(ip);
    logger.info(`IP desbloqueada manualmente: ${ip}`);
    return true;
  }
  return false;
};

// Función para bloquear IP manualmente
const blockIP = (ip, reason = 'Manual') => {
  blockedIPs.add(ip);
  const ipData = suspiciousIPs.get(ip) || {};
  ipData.blockedAt = Date.now();
  ipData.blockReason = reason;
  suspiciousIPs.set(ip, ipData);
  logger.security(`IP bloqueada manualmente: ${ip}`, { reason });
};

module.exports = {
  ddosProtection,
  detectAttackPatterns,
  requestSizeLimit,
  slowlorisProtection,
  getStats,
  unblockIP,
  blockIP,
};