import { defineMiddleware } from 'astro:middleware';

/**
 * Emits the site-wide security header set. Astro does not attach these to
 * statically-built responses at runtime on a shared host — but `preview` uses
 * them locally, and when Cloudflare Transform Rules are configured (per
 * docs/superpowers/specs/2026-04-24-cameleer-website-design.md §5.3) the
 * edge re-emits the same set for the prod origin. Having both is defense
 * in depth.
 */
export function buildSecurityHeaders(): Record<string, string> {
  const csp = [
    "default-src 'self'",
    "img-src 'self' data:",
    // Astro's scoped-style system injects inline style attributes at build time;
    // 'unsafe-inline' here is required until we migrate to a hash/nonce strategy.
    "style-src 'self' 'unsafe-inline'",
    "font-src 'self'",
    "script-src 'self'",
    "connect-src 'self'",
    "frame-ancestors 'none'",
    "base-uri 'self'",
    // No forms on this marketing site today (all auth redirects go to app.cameleer.io
    // as plain <a> navigations). If a future form is added, relax to 'self' or an allow-list.
    "form-action 'none'",
    "object-src 'none'",
  ].join('; ');

  // Must match .htaccess and the Cloudflare Transform Rule in OPERATOR-CHECKLIST.md.
  const permissionsPolicy = [
    'geolocation=()',
    'microphone=()',
    'camera=()',
    'payment=()',
    'usb=()',
  ].join(', ');

  return {
    'Content-Security-Policy': csp,
    'X-Frame-Options': 'DENY',
    'X-Content-Type-Options': 'nosniff',
    'Referrer-Policy': 'strict-origin-when-cross-origin',
    'Permissions-Policy': permissionsPolicy,
    'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload',
  };
}

export const onRequest = defineMiddleware(async (_context, next) => {
  const response = await next();
  const headers = buildSecurityHeaders();
  for (const [name, value] of Object.entries(headers)) {
    response.headers.set(name, value);
  }
  return response;
});
