"""FastAPI/Starlette middleware for JWT authentication."""

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse

from ..config import AuthSettings
from ..exceptions import AuthenticationError
from ..models import AuthenticatedUser
from ..token import get_key_cache, validate_token


class AuthMiddleware(BaseHTTPMiddleware):
    """Validates Bearer JWT tokens on /api/* routes.

    Usage:
        from conduit_auth.fastapi import AuthMiddleware
        from conduit_auth import AuthSettings

        settings = AuthSettings()
        app.add_middleware(AuthMiddleware, settings=settings)
    """

    def __init__(self, app, settings: AuthSettings) -> None:
        super().__init__(app)
        self.settings = settings
        self._key_cache = get_key_cache()

    async def dispatch(self, request: Request, call_next):
        path = request.url.path

        # Skip excluded paths (health checks, etc.)
        if path in self.settings.AUTH_EXCLUDE_PATHS:
            return await call_next(request)

        # Only protect /api/* routes — static assets are served by nginx
        if not path.startswith("/api/"):
            return await call_next(request)

        # Dev bypass — injects a mock user
        if self.settings.AUTH_DISABLED:
            request.state.user = AuthenticatedUser(
                tenant_id="dev-tenant-00000000",
                user_id="dev-user-00000000",
                email="dev@localhost",
                display_name="Dev User",
                roles=[],
                raw_claims={},
            )
            return await call_next(request)

        # Extract Bearer token
        auth_header = request.headers.get("Authorization", "")
        if not auth_header.startswith("Bearer "):
            return JSONResponse(
                {"error": "Missing or invalid Authorization header"},
                status_code=401,
            )
        token = auth_header[7:]

        # Validate
        try:
            jwks_keys = await self._key_cache.get_keys_async(self.settings)
            user = validate_token(token, jwks_keys, self.settings)
        except AuthenticationError as e:
            return JSONResponse({"error": str(e)}, status_code=401)

        request.state.user = user
        return await call_next(request)
