import { Request, Response, NextFunction } from 'express';
import crypto from 'crypto';
import { env } from '../config/env';
import { sendError } from '../utils/helpers';

const CSRF_COOKIE = 'XSRF-TOKEN';
const CSRF_HEADER = 'x-csrf-token';

function generateToken(): string {
  return crypto
    .createHmac('sha256', env.CSRF_SECRET)
    .update(crypto.randomBytes(16).toString('hex'))
    .digest('hex');
}

export function csrfIssue(
  req: Request,
  res: Response,
  next: NextFunction
) {
  if (!req.cookies || !req.cookies[CSRF_COOKIE]) {
    res.cookie(CSRF_COOKIE, generateToken(), {
      httpOnly: false,
      sameSite: 'lax',
      secure: env.NODE_ENV === 'production',
    });
  }
  return next();
}

export function csrfProtect(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE'];
  if (safeMethods.includes(req.method)) {
    return next();
  }

  const cookieToken = req.cookies ? req.cookies[CSRF_COOKIE] : undefined;

  // Stateless Bearer APIs do not carry the CSRF cookie; skip validation
  // for them. Cookie-based flows are still protected below.
  if (!cookieToken) {
    return next();
  }

  const headerToken =
    (req.headers[CSRF_HEADER] as string) ||
    (req.headers['x-xsrf-token'] as string);

  if (!headerToken || cookieToken !== headerToken) {
    return sendError(res, 'Invalid CSRF token', 403);
  }
  return next();
}

export { CSRF_COOKIE, CSRF_HEADER };
