const csrf = require("csrf");
const cookieParser = require("cookie-parser");

// Initialize CSRF token generator
const tokens = new csrf();

// Generate a secret for signing tokens
const secret = tokens.secretSync();

// CSRF middleware using double submit cookie pattern
const csrfProtection = (req, res, next) => {
  // Skip CSRF for safe methods
  if (["GET", "HEAD", "OPTIONS"].includes(req.method)) {
    return next();
  }

  // Get token from header or body
  const token =
    req.headers["x-csrf-token"] || req.body.csrfToken || req.query.csrfToken;

  // Get token from cookie
  const cookieToken = req.cookies && req.cookies["csrf-token"];

  // Verify both tokens exist and match
  if (!token || !cookieToken || token !== cookieToken) {
    return res.status(403).json({
      error: "Invalid CSRF token",
      code: "CSRF_TOKEN_MISMATCH",
    });
  }

  // Verify token is valid
  if (!tokens.verify(secret, token)) {
    return res.status(403).json({
      error: "Invalid CSRF token",
      code: "CSRF_TOKEN_INVALID",
    });
  }

  next();
};

// Middleware to generate and send CSRF token
const generateCSRFToken = (req, res, next) => {
  const token = tokens.create(secret);

  // Set token in cookie (httpOnly for security)
  res.cookie("csrf-token", token, {
    httpOnly: true,
    secure: process.env.NODE_ENV !== "dev",
    sameSite: "strict",
    maxAge: 60 * 60 * 1000, // 1 hour
  });

  // Also provide token in header for client to use
  res.set("X-CSRF-Token", token);

  // Make token available to response
  res.locals.csrfToken = token;

  next();
};

// Route to get CSRF token (for initial page loads)
const getCSRFToken = (req, res) => {
  const token = tokens.create(secret);

  res.cookie("csrf-token", token, {
    httpOnly: true,
    secure: process.env.NODE_ENV !== "dev",
    sameSite: "strict",
    maxAge: 60 * 60 * 1000,
  });

  res.set("X-CSRF-Token", token);
  res.status(204).send();
};

module.exports = {
  csrfProtection,
  generateCSRFToken,
  getCSRFToken,
  cookieParser: cookieParser(),
};
