import { defineMiddleware } from 'astro/middleware'

function createNonce(): string {
  const bytes = new Uint8Array(16)
  crypto.getRandomValues(bytes)
  return Buffer.from(bytes).toString('base64url')
}

function appendNonceToScriptSrc(csp: string, nonce: string): string {
  if (!csp.includes('script-src')) {
    return `${csp}; script-src 'self' 'nonce-${nonce}'`
  }

  return csp.replace(/script-src\s+([^;]+)/, (full, sources: string) => {
    if (sources.includes(`'nonce-${nonce}'`)) return full
    return `script-src ${sources} 'nonce-${nonce}'`
  })
}

/**
 * Security headers middleware.
 *
 * Astro owns the base CSP. This middleware adds a per-request nonce for the
 * blocking theme boot script and preserves the rest of Astro's directives.
 */
export const onRequest = defineMiddleware(async (context, next) => {
  const nonce = createNonce()
  context.locals.nonce = nonce

  const res = await next()
  const csp = res.headers.get('content-security-policy')
  if (csp) {
    res.headers.set('content-security-policy', appendNonceToScriptSrc(csp, nonce))
  }
  res.headers.set('X-Frame-Options', 'DENY')
  res.headers.set('X-Content-Type-Options', 'nosniff')
  return res
})
