import { createContext } from "react";
import crypto from "node:crypto";

export interface CspMiddlewareOptions {
  reportOnly?: boolean;
}

/**
 * React context exposing the per-request CSP nonce.
 * Default is "" — client-side components read empty string (no-op).
 */
export const CspNonceContext = createContext<string>("");

/**
 * Factory returning express-style middleware that:
 * 1. Generates a per-request nonce
 * 2. Sets the CSP header (or Report-Only variant)
 * 3. Attaches `req.cspNonce` for downstream middleware
 */
export function cspMiddleware(options?: CspMiddlewareOptions) {
  const headerName = options?.reportOnly
    ? "Content-Security-Policy-Report-Only"
    : "Content-Security-Policy";

  return (
    req: Record<string, unknown>,
    res: { setHeader(name: string, value: string): void },
    next: () => void,
  ): void => {
    const nonce = crypto.randomUUID();

    const policy = [
      `default-src 'self'`,
      `script-src 'self' 'nonce-${nonce}'`,
      `style-src 'self' 'unsafe-inline'`,
      `img-src 'self' data: https:`,
      `font-src 'self'`,
      `connect-src 'self' https:`,
      `frame-ancestors 'self'`,
      `base-uri 'self'`,
      `form-action 'self'`,
    ].join("; ");

    res.setHeader(headerName, policy);
    req["cspNonce"] = nonce;

    next();
  };
}
