/**
 * CSRF token utilities
 * Generates and validates CSRF tokens to prevent cross-site request forgery
 */
import crypto from 'crypto';

const CSRF_TOKEN_LENGTH = 32;
const CSRF_TOKEN_EXPIRY = 3600000; // 1 hour in milliseconds

interface TokenData {
  sessionId: string;
  expiresAt: number;
}

// In-memory token store (for production, use Redis or database)
const tokenStore: Map<string, TokenData> = new Map();

// Cleanup expired tokens periodically
setInterval(() => {
  const now = Date.now();
  for (const [token, data] of tokenStore.entries()) {
    if (data.expiresAt < now) {
      tokenStore.delete(token);
    }
  }
}, 300000); // Clean every 5 minutes

/**
 * Generate a new CSRF token
 * @param sessionId - Unique identifier for the user session (e.g., cookie ID)
 * @returns The generated CSRF token
 */
export function generateCsrfToken(sessionId: string): string {
  const token = crypto.randomBytes(CSRF_TOKEN_LENGTH).toString('hex');
  const expiresAt = Date.now() + CSRF_TOKEN_EXPIRY;
  
  tokenStore.set(token, {
    sessionId,
    expiresAt,
  });
  
  return token;
}

/**
 * Validate a CSRF token
 * @param token - The token to validate
 * @param sessionId - The session ID to validate against
 * @returns True if token is valid, false otherwise
 */
export function validateCsrfToken(token: string | null | undefined, sessionId: string | null | undefined): boolean {
  if (!token || !sessionId) {
    return false;
  }
  
  const data = tokenStore.get(token);
  
  if (!data) {
    return false;
  }
  
  // Check expiry
  if (data.expiresAt < Date.now()) {
    tokenStore.delete(token);
    return false;
  }
  
  // Check session ID match
  if (data.sessionId !== sessionId) {
    return false;
  }
  
  // Token is valid - consume it (one-time use)
  tokenStore.delete(token);
  
  return true;
}

/**
 * Get token store size (for monitoring)
 */
export function getTokenStoreSize(): number {
  return tokenStore.size;
}
