/**
 * TASKMATE - CSRF Schutz
 * ======================
 * Cross-Site Request Forgery Schutz
 *
 * Vereinfachtes System: Token wird beim Login generiert und bleibt
 * für die gesamte Sitzung gültig (24 Stunden).
 */

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

// CSRF-Tokens speichern (in-memory, pro User)
const csrfTokens = new Map();

// Token-Gültigkeit: 24 Stunden
const TOKEN_VALIDITY = 24 * 60 * 60 * 1000;

/**
 * CSRF-Token generieren
 */
function generateToken(userId) {
  const token = crypto.randomBytes(32).toString('hex');
  const expires = Date.now() + TOKEN_VALIDITY;

  csrfTokens.set(userId, { token, expires });
  cleanupExpiredTokens();

  return token;
}

/**
 * CSRF-Token validieren
 */
function validateToken(userId, token) {
  const stored = csrfTokens.get(userId);

  if (!stored) {
    return false;
  }

  if (Date.now() > stored.expires) {
    csrfTokens.delete(userId);
    return false;
  }

  return stored.token === token;
}

/**
 * Abgelaufene Tokens aufräumen
 */
function cleanupExpiredTokens() {
  const now = Date.now();
  for (const [userId, data] of csrfTokens.entries()) {
    if (now > data.expires) {
      csrfTokens.delete(userId);
    }
  }
}

// Regelmäßig aufräumen (alle 30 Minuten)
setInterval(cleanupExpiredTokens, 30 * 60 * 1000);

/**
 * Express Middleware
 */
function csrfProtection(req, res, next) {
  // GET-Anfragen sind sicher (lesen nur)
  if (req.method === 'GET') {
    return next();
  }

  // User muss authentifiziert sein
  if (!req.user) {
    return next();
  }

  const userId = req.user.id;

  // Token aus Header oder Body
  const token = req.headers['x-csrf-token'] || req.body?._csrf;

  // Wenn kein Token vom Client gesendet oder kein Token auf Server gespeichert
  if (!token || !csrfTokens.has(userId)) {
    const newToken = generateToken(userId);
    logger.info(`CSRF: Token missing or not stored for user ${userId}, generated new token`);
    return res.status(403).json({
      error: 'CSRF-Token fehlt oder abgelaufen',
      csrfToken: newToken,
      code: 'CSRF_ERROR'
    });
  }

  // Token validieren
  if (!validateToken(userId, token)) {
    const newToken = generateToken(userId);
    logger.info(`CSRF: Token mismatch for user ${userId}`);
    return res.status(403).json({
      error: 'Ungültiges CSRF-Token',
      csrfToken: newToken,
      code: 'CSRF_ERROR'
    });
  }

  // Token ist gültig - KEIN neuer Token generiert (bleibt für die Sitzung gleich)
  next();
}

/**
 * Aktuellen Token für User abrufen (oder neuen generieren)
 */
function getTokenForUser(userId) {
  const stored = csrfTokens.get(userId);

  if (stored && Date.now() < stored.expires) {
    return stored.token;
  }

  return generateToken(userId);
}

module.exports = csrfProtection;
module.exports.generateToken = generateToken;
module.exports.getTokenForUser = getTokenForUser;
