"""
Security headers middleware.

Adds standard security headers to every HTTP response:
- HSTS (production only)
- X-Content-Type-Options
- X-Frame-Options
- Referrer-Policy
- Permissions-Policy
- Content-Security-Policy (report-only by default)
"""

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response
from typing import Callable

from app.core.config import settings


def _build_csp_directive() -> str:
    """Build the CSP directive string from config."""
    script_sources = "'self' https://us.i.posthog.com https://*.sentry.io"
    if settings.CSP_EXTRA_SCRIPT_SOURCES:
        script_sources += " " + " ".join(settings.CSP_EXTRA_SCRIPT_SOURCES)

    connect_sources = (
        "'self' https://us.posthog.com https://us.i.posthog.com "
        "https://*.sentry.io https://api.resolutionflow.com"
    )
    if settings.CSP_EXTRA_CONNECT_SOURCES:
        connect_sources += " " + " ".join(settings.CSP_EXTRA_CONNECT_SOURCES)

    return "; ".join([
        "default-src 'self'",
        f"script-src {script_sources}",
        "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
        "font-src 'self' https://fonts.gstatic.com",
        "img-src 'self' data: blob:",
        f"connect-src {connect_sources}",
        "frame-ancestors 'none'",
        "base-uri 'self'",
        "form-action 'self'",
    ])


class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    """Add security headers to every response."""

    def __init__(self, app):
        super().__init__(app)
        # Pre-build CSP at startup so we don't rebuild per-request
        self._csp = _build_csp_directive()

    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        response = await call_next(request)

        # Always set these headers
        response.headers["X-Content-Type-Options"] = "nosniff"
        response.headers["X-Frame-Options"] = "DENY"
        response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
        response.headers["Permissions-Policy"] = (
            "camera=(), microphone=(), geolocation=()"
        )

        # HSTS only in production (avoid locking localhost into HTTPS)
        if not settings.DEBUG:
            response.headers["Strict-Transport-Security"] = (
                "max-age=31536000; includeSubDomains"
            )

        # CSP — report-only or enforcing based on config
        csp_header = (
            "Content-Security-Policy-Report-Only"
            if settings.CSP_REPORT_ONLY
            else "Content-Security-Policy"
        )
        response.headers[csp_header] = self._csp

        return response
