# coding: utf-8
from __future__ import absolute_import, unicode_literals

from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from rest_framework_sso import claims
from rest_framework_sso.models import SessionToken
from rest_framework_sso.serializers import SessionTokenSerializer, AuthorizationTokenSerializer
from rest_framework_sso.settings import api_settings

import logging

logger = logging.getLogger(__name__)

create_session_payload = api_settings.CREATE_SESSION_PAYLOAD
create_authorization_payload = api_settings.CREATE_AUTHORIZATION_PAYLOAD
encode_jwt_token = api_settings.ENCODE_JWT_TOKEN
decode_jwt_token = api_settings.DECODE_JWT_TOKEN


class BaseAPIView(APIView):
    """
    Base API View that various JWT interactions inherit from.
    """

    throttle_classes = ()
    permission_classes = ()
    serializer_class = None

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return {"request": self.request, "view": self}

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        You may want to override this if you need to provide different
        serializations depending on the incoming request.
        (Eg. admins get full serialization, others get basic serialization)
        """
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method." % self.__class__.__name__
        )
        return self.serializer_class

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        kwargs["context"] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)


class ObtainSessionTokenView(BaseAPIView):
    """
    Returns a JSON Web Token that can be used for authenticated requests.
    """

    permission_classes = ()
    serializer_class = SessionTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data["user"]
        session_token = SessionToken.objects.active().filter(user=user).with_user_agent(request=request).first()
        if session_token is None:
            session_token = SessionToken(user=user)
        session_token.update_attributes(request=request)
        session_token.save()
        payload = create_session_payload(session_token=session_token, user=user)
        jwt_token = encode_jwt_token(payload=payload)
        return Response({"token": jwt_token})


class ObtainAuthorizationTokenView(BaseAPIView):
    """
    Returns a JSON Web Token that can be used for authenticated requests.
    """

    permission_classes = (IsAuthenticated,)
    serializer_class = AuthorizationTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        if hasattr(request.auth, "get") and request.auth.get(claims.SESSION_ID):
            try:
                session_token = SessionToken.objects.active().get(
                    pk=request.auth.get(claims.SESSION_ID), user=request.user
                )
            except SessionToken.DoesNotExist:
                return Response({"detail": "Invalid token."}, status=status.HTTP_401_UNAUTHORIZED)
        else:
            session_token = (
                SessionToken.objects.active().filter(user=request.user).with_user_agent(request=request).first()
            )
            if session_token is None:
                session_token = SessionToken(user=request.user)

        session_token.update_attributes(request=request)
        session_token.save()
        payload = create_authorization_payload(
            session_token=session_token, user=request.user, **serializer.validated_data
        )
        jwt_token = encode_jwt_token(payload=payload)
        return Response({"token": jwt_token})


obtain_session_token = ObtainSessionTokenView.as_view()
obtain_authorization_token = ObtainAuthorizationTokenView.as_view()

# coding: utf-8
from __future__ import absolute_import, unicode_literals

from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from rest_framework_sso import claims
from rest_framework_sso.models import SessionToken
from rest_framework_sso.serializers import SessionTokenSerializer, AuthorizationTokenSerializer
from rest_framework_sso.settings import api_settings

import logging

logger = logging.getLogger(__name__)

create_session_payload = api_settings.CREATE_SESSION_PAYLOAD
create_authorization_payload = api_settings.CREATE_AUTHORIZATION_PAYLOAD
encode_jwt_token = api_settings.ENCODE_JWT_TOKEN
decode_jwt_token = api_settings.DECODE_JWT_TOKEN


class BaseAPIView(APIView):
    """
    Base API View that various JWT interactions inherit from.
    """

    throttle_classes = ()
    permission_classes = ()
    serializer_class = None

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return {"request": self.request, "view": self}

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        You may want to override this if you need to provide different
        serializations depending on the incoming request.
        (Eg. admins get full serialization, others get basic serialization)
        """
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method." % self.__class__.__name__
        )
        return self.serializer_class

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        kwargs["context"] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)


class ObtainSessionTokenView(BaseAPIView):
    """
    Returns a JSON Web Token that can be used for authenticated requests.
    """

    permission_classes = ()
    serializer_class = SessionTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data["user"]
        session_token = SessionToken.objects.active().filter(user=user).with_user_agent(request=request).first()
        if session_token is None:
            session_token = SessionToken(user=user)
        session_token.update_attributes(request=request)
        session_token.save()
        payload = create_session_payload(session_token=session_token, user=user)
        jwt_token = encode_jwt_token(payload=payload)
        return Response({"token": jwt_token})


class ObtainAuthorizationTokenView(BaseAPIView):
    """
    Returns a JSON Web Token that can be used for authenticated requests.
    """

    permission_classes = (IsAuthenticated,)
    serializer_class = AuthorizationTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        if hasattr(request.auth, "get") and request.auth.get(claims.SESSION_ID):
            try:
                session_token = SessionToken.objects.active().get(
                    pk=request.auth.get(claims.SESSION_ID), user=request.user
                )
            except SessionToken.DoesNotExist:
                return Response({"detail": "Invalid token."}, status=status.HTTP_401_UNAUTHORIZED)
        else:
            session_token = (
                SessionToken.objects.active().filter(user=request.user).with_user_agent(request=request).first()
            )
            if session_token is None:
                session_token = SessionToken(user=request.user)

        session_token.update_attributes(request=request)
        session_token.save()
        payload = create_authorization_payload(
            session_token=session_token, user=request.user, **serializer.validated_data
        )
        jwt_token = encode_jwt_token(payload=payload)
        return Response({"token": jwt_token})


obtain_session_token = ObtainSessionTokenView.as_view()
obtain_authorization_token = ObtainAuthorizationTokenView.as_view()

# coding: utf-8 Base API View that various JWT interactions inherit from. Extra context provided to the serializer class. Return the class to use for the serializer.         Defaults to using `self.serializer_class`.         You may want to override this if you need to provide different         serializations depending on the incoming request.         (Eg. admins get full serialization, others get basic serialization) Return the serializer instance that should be used for validating and         deserializing input, and for serializing output. Returns a JSON Web Token that can be used for authenticated requests. Returns a JSON Web Token that can be used for authenticated requests.