/**
 * Security Middleware
 * Handles rate limiting, IP blocking, and failed login attempts
 */

// Dictionary to track failed login attempts
const failedLoginAttempts = {};

// Constants
const MAX_FAILED_ATTEMPTS = 30;
const BLOCK_DURATION = 30 * 60 * 1000; // 30 minutes

/**
 * Block user after too many failed attempts
 */
function blockUser(username) {
  failedLoginAttempts[username] = Date.now() + BLOCK_DURATION;
}

/**
 * Check if user is blocked
 */
function isUserBlocked(username) {
  const now = Date.now();
  return failedLoginAttempts[username] && failedLoginAttempts[username] > now;
}

/**
 * Clear failed attempts for user (on successful login)
 */
function clearFailedAttempts(username) {
  delete failedLoginAttempts[username];
}

/**
 * Middleware to check if user is blocked before login
 */
function checkBlocked(req, res, next) {
  const { username } = req.body;

  console.log('checkBlocked');

  if (!username) {
    return res.status(400).json({
      message: 'Username mancante',
    });
  }

  if (isUserBlocked(username)) {
    const text = `Utente bloccato. Riprova più tardi. (username=${username})`;
    console.log(text);
    return res.status(403).json({
      message: 'Utente bloccato. Riprova più tardi.',
    });
  }

  next();
}

/**
 * Get failed attempts count for a user
 */
function getFailedAttempts(username) {
  return failedLoginAttempts[username] || 0;
}

/**
 * Increment failed attempts
 */
function incrementFailedAttempts(username) {
  if (typeof failedLoginAttempts[username] === 'number') {
    failedLoginAttempts[username]++;
  } else {
    failedLoginAttempts[username] = 1;
  }
  return failedLoginAttempts[username];
}

/**
 * Check if user should be blocked after this attempt
 */
function shouldBlockUser(username) {
  return (failedLoginAttempts[username] || 0) >= MAX_FAILED_ATTEMPTS;
}

/**
 * Middleware to rate limit API requests per IP
 */
const requestCounts = {};
const REQUEST_WINDOW = 60 * 1000; // 1 minute
const MAX_REQUESTS = 100; // per window

function rateLimitByIP(req, res, next) {
  const tools = require('../tools/general');
  const ip = tools.getiPAddressUser(req);
  const now = Date.now();

  if (!requestCounts[ip]) {
    requestCounts[ip] = {
      count: 1,
      resetTime: now + REQUEST_WINDOW,
    };
    return next();
  }

  if (now > requestCounts[ip].resetTime) {
    // Reset window
    requestCounts[ip] = {
      count: 1,
      resetTime: now + REQUEST_WINDOW,
    };
    return next();
  }

  if (requestCounts[ip].count >= MAX_REQUESTS) {
    return res.status(429).json({
      message: 'Troppi tentativi. Riprova più tardi.',
    });
  }

  requestCounts[ip].count++;
  next();
}

/**
 * Clean up old blocked users (run periodically)
 */
function cleanupBlockedUsers() {
  const now = Date.now();
  Object.keys(failedLoginAttempts).forEach((username) => {
    if (typeof failedLoginAttempts[username] === 'number' && failedLoginAttempts[username] < now) {
      delete failedLoginAttempts[username];
    }
  });
}

// Run cleanup every 10 minutes
setInterval(cleanupBlockedUsers, 10 * 60 * 1000);

module.exports = {
  checkBlocked,
  blockUser,
  isUserBlocked,
  clearFailedAttempts,
  getFailedAttempts,
  incrementFailedAttempts,
  shouldBlockUser,
  rateLimitByIP,
  MAX_FAILED_ATTEMPTS,
  BLOCK_DURATION,
};
