from typing import Any

from fastapi import Request, Response
from fastapi.security import HTTPAuthorizationCredentials

from agentflow_cli.src.app.core import logger
from agentflow_cli.src.app.core.auth.base_auth import BaseAuth
from agentflow_cli.src.app.core.config.settings import get_settings
from agentflow_cli.src.app.core.exceptions import UserAccountError


try:
    import jwt
except ImportError:  # pragma: no cover
    jwt = None  # type: ignore[assignment]


class JwtAuth(BaseAuth):
    def authenticate(
        self,
        request: Request,
        response: Response,
        credential: HTTPAuthorizationCredentials,
    ) -> dict[str, Any] | None:
        """No authentication is required, so return None."""
        """
        Get the current user based on the provided HTTP
        Authorization credentials.

        Args:
            res (Response): The response object to set headers if needed.
            credential (HTTPAuthorizationCredentials): The HTTP Authorization
            credentials obtained from the request.

        Returns:
            UserSchema: A UserSchema object containing the decoded user information.

        Raises:
            HTTPException: If the credentials are missing.
            UserAccountError: If there are token verification errors such as
                RevokedIdTokenError,
                UserDisabledError,
                InvalidIdTokenError,
                or any other unexpected exceptions.
        """

        if credential is None:
            raise UserAccountError(
                message="Invalid token, please login again",
                error_code="REVOKED_TOKEN",
            )

        settings = get_settings()
        jwt_secret_key = settings.JWT_SECRET_KEY
        jwt_algorithm = settings.JWT_ALGORITHM

        token = credential.credentials

        if jwt is None:
            raise ImportError(
                "PyJWT is required for JWT authentication. "
                'Install with `pip install "10xscale-agentflow-cli[jwt]"`'
            )

        if jwt_secret_key is None or jwt_algorithm is None:
            raise UserAccountError(
                message="JWT settings are not configured",
                error_code="JWT_SETTINGS_NOT_CONFIGURED",
            )

        try:
            decoded_token = jwt.decode(
                token,
                jwt_secret_key,
                algorithms=[jwt_algorithm],
            )
        except jwt.ExpiredSignatureError:
            raise UserAccountError(
                message="Token has expired, please login again",
                error_code="EXPIRED_TOKEN",
            )
        except jwt.InvalidTokenError as err:
            logger.exception("JWT AUTH ERROR", exc_info=err)
            raise UserAccountError(
                message="Invalid token, please login again",
                error_code="INVALID_TOKEN",
            )

        response.headers["WWW-Authenticate"] = 'Bearer realm="auth_required"'

        # check if user_id exists in the token
        if "user_id" not in decoded_token:
            raise UserAccountError(
                message="Invalid token, user_id missing",
                error_code="INVALID_TOKEN",
            )
        return decoded_token
