import json
import logging

from oic.oic.message import AuthorizationRequest

from django.http import JsonResponse
from django.views.generic import View
from django_forest.authentication.exception import AuthenticationClientException

from django_forest.authentication.oidc.client_manager import OidcClientManager
from django_forest.authentication.utils import authentication_exception, get_callback_url
from django_forest.utils.error_handler import MESSAGES


logger = logging.getLogger(__name__)

# Based on https://pyoidc.readthedocs.io/en/latest/examples/rp.html


class IndexView(View):

    def _get_payload(self, request):
        try:
            payload = json.loads(request.body)
        except json.JSONDecodeError:
            raise AuthenticationClientException(
                'request.body is not a valid json object'
            )
        return payload

    def _get_rendering_id(self, payload):
        try:
            rendering_id = payload['renderingId']
        except KeyError:
            raise AuthenticationClientException(
                MESSAGES['SERVER_TRANSACTION']['MISSING_RENDERING_ID']
            )
        if not any(isinstance(rendering_id, _type) for _type in [str, int]):
            raise AuthenticationClientException(MESSAGES['SERVER_TRANSACTION']['INVALID_RENDERING_ID'])
        return int(rendering_id)

    def _get_authorization_url(self, redirect_url, state):
        client = OidcClientManager.get_client_for_callback_url(redirect_url)
        logger.debug(f"client_id: {client.client_id}")
        args = {
            'client_id': client.client_id,
            'response_type': 'code',
            'scope': ['openid', 'email', 'profile'],
            'state': json.dumps(state),
            'redirect_uri': redirect_url,
        }
        auth_req: AuthorizationRequest = client.construct_AuthorizationRequest(request_args=args)
        authorization_url = auth_req.request(client.authorization_endpoint)

        return authorization_url

    @authentication_exception
    def post(self, request, *args, **kwargs):
        payload = self._get_payload(request)
        rendering_id = self._get_rendering_id(payload)
        callback_url = get_callback_url()
        authorization_url = self._get_authorization_url(callback_url, {'renderingId': rendering_id})
        return JsonResponse({'authorizationUrl': authorization_url})
