"""FastAPI integration — Depends()-compatible auth callable."""

from fastapi import FastAPI, HTTPException, Request
from starlette.responses import JSONResponse
from starlette.status import HTTP_401_UNAUTHORIZED

from ._config import AuthConfig
from ._models import AuthenticatedUser, ErrorFormat
from ._token_extraction import extract_token
from ._verifier import AuthenticationError, AuthVerifier

_WWW_AUTHENTICATE = {"WWW-Authenticate": "Bearer"}


class _OpenAIAuthError(HTTPException):
    """Auth error that carries the original message for OpenAI-format rendering.

    Inherits HTTPException so that without ``install()`` it falls back to
    FastAPI's default ``{"detail": "..."}`` response instead of a 500.
    """

    def __init__(self, message: str) -> None:
        super().__init__(
            status_code=HTTP_401_UNAUTHORIZED,
            detail=message,
            headers=_WWW_AUTHENTICATE,
        )
        self.message = message


async def _openai_auth_error_handler(
    request: Request, exc: _OpenAIAuthError
) -> JSONResponse:
    return JSONResponse(
        content={
            "error": {
                "message": exc.message,
                "type": "invalid_request_error",
                "param": None,
                "code": "invalid_api_key",
            }
        },
        status_code=HTTP_401_UNAUTHORIZED,
        headers=_WWW_AUTHENTICATE,
    )


class FastAPIAuth:
    """Callable dependency for FastAPI that verifies bearer tokens.

    Usage::

        auth = FastAPIAuth(config)
        app = FastAPI()

        @app.get("/protected")
        def protected(user: AuthenticatedUser = Depends(auth)):
            return {"subject": user.subject}
    """

    def __init__(
        self,
        config: AuthConfig,
        *,
        error_format: ErrorFormat = ErrorFormat.DEFAULT,
    ):
        self._verifier = AuthVerifier(config)
        self._error_format = ErrorFormat(error_format)

    def __call__(self, request: Request) -> AuthenticatedUser:
        token = extract_token(request)
        try:
            return self._verifier.verify_token(token)
        except AuthenticationError as exc:
            if self._error_format == ErrorFormat.OPENAI:
                raise _OpenAIAuthError(str(exc)) from exc
            raise HTTPException(
                status_code=HTTP_401_UNAUTHORIZED,
                detail=str(exc),
                headers=_WWW_AUTHENTICATE,
            ) from exc

    def install(self, app: FastAPI) -> None:
        """Register exception handlers on the FastAPI app.

        For ``ErrorFormat.OPENAI``, this adds a handler that renders
        authentication errors in the OpenAI-compatible JSON format.
        """
        if self._error_format == ErrorFormat.OPENAI:
            app.add_exception_handler(_OpenAIAuthError, _openai_auth_error_handler)
