"""Resource Server Authentication"""

import base64
import binascii
import logging

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

from mozilla_django_oidc.contrib.drf import OIDCAuthentication

from .backend import ResourceServerBackend, ResourceServerImproperlyConfiguredBackend
from .clients import AuthorizationServerClient

logger = logging.getLogger(__name__)


class ResourceServerAuthentication(OIDCAuthentication):
    """Authenticate clients using the token received from the authorization server."""

    def __init__(self):
        """Require authentication to be configured in order to instantiate."""
        super().__init__()

        try:
            authorization_server_client = AuthorizationServerClient(
                url=settings.OIDC_OP_URL,
                verify_ssl=settings.OIDC_VERIFY_SSL,
                timeout=settings.OIDC_TIMEOUT,
                proxy=settings.OIDC_PROXY,
                url_jwks=settings.OIDC_OP_JWKS_ENDPOINT,
                url_introspection=settings.OIDC_OP_INTROSPECTION_ENDPOINT,
            )
            self.backend = ResourceServerBackend(authorization_server_client)

        except ImproperlyConfigured as err:
            message = "Resource Server authentication is disabled"
            logger.debug("%s. Exception: %s", message, err)
            self.backend = ResourceServerImproperlyConfiguredBackend()

    def get_access_token(self, request):
        """Retrieve and decode the access token from the request.

        This method overrides the 'get_access_token' method from the parent class,
        to support service providers that would base64 encode the bearer token.
        """

        access_token = super().get_access_token(request)

        try:
            access_token = base64.b64decode(access_token).decode("utf-8")
        except (binascii.Error, TypeError):
            pass

        return access_token

    def authenticate(self, request):
        """
        Authenticate the request and return a tuple of (user, token) or None.

        We override the 'authenticate' method from the parent class to store
        the introspected token audience inside the request.
        """
        result = super().authenticate(request)  # Might raise AuthenticationFailed

        if result is None:  # Case when there is no access token
            return None

        # Note: at this stage, the request is a "drf_request" object
        request.resource_server_token_audience = self.backend.token_origin_audience

        return result
