"""
we use middlewares in this project and this file store classes of our middlewares
"""
import jwt
from django.conf import settings
from django.utils import timezone
from rest_framework import status

from authenticate.models import UserJWT
from institute.models import APIKey, InstituteJWT
from utils.myresponse import MyResponse


class AuthorizatorMiddleware:

    def __init__(self, get_response, accept_user_token=False, accept_server_token=False,
                 accept_server_api_key=False, optional_authentication=False):
        self.get_response = get_response
        self.accept_user_token = accept_user_token
        self.accept_server_token = accept_server_token
        self.accept_server_api_key = accept_server_api_key
        self.optional_authentication = optional_authentication
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        response = self.get_response(request)
        # Code to be executed for each request/response after
        # the view is called.
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        # ----------------------------- Block 1 -----------------------------
        # get token and api_key from request and return error if both of them come in request
        if request.method == 'POST':
            token = request.data.get('token')
            api_key = request.data.get('api_key')
        else:
            token = request.GET.get('token')
            api_key = request.GET.get('api_key')

        if token and api_key:
            return MyResponse(request, {'status': 'error', 'message': 'you can not send both token and api_key'},
                              status=status.HTTP_400_BAD_REQUEST)
        # ----------------------------- Block 2 -----------------------------
        success = False
        message = "Authorization failed."

        if self.accept_user_token:
            # de
            # coding and validating of user token
            try:
                jwt.decode(token, settings.SECRET_KEY, issuer=settings.JWT_ISSUER,
                           audience=settings.JWT_AUDIENCE, algorithms=['HS256'])

                try:
                    userjwt_record = UserJWT.objects.get(
                        token=token, expire_at__gt=timezone.now())
                    request.middleware_token_record = userjwt_record
                    request.middleware_user = userjwt_record.user

                    success = True
                except:
                    message = "Authorization failed. Cannot find a user corresponding to the token*."
                    success = False
            except:
                message = "Authorization failed. Cannot decode the token*."
                success = False

        if success:
            return

        if self.accept_server_token:
            # decoding and validating of server token
            try:
                jwt.decode(token, settings.SECRET_KEY, issuer=settings.JWT_ISSUER,
                           audience=settings.JWT_AUDIENCE, algorithms=['HS256'])

                try:
                    institute_jwt_record = InstituteJWT.objects.get(
                        token=token, expire_at__gt=timezone.now())
                    request.middleware_api_key = institute_jwt_record.api_key
                    request.middleware_institute = institute_jwt_record.api_key.institute

                    success = True
                except:
                    message = "Authorization failed. Cannot find a user corresponding to the token."
                    success = False
            except:
                message = "Authorization failed. Cannot decode the token."
                success = False

        if success:
            return

        if self.accept_server_api_key:
            # decoding and validating of server api key
            try:
                jwt.decode(api_key, settings.SECRET_KEY, issuer=settings.JWT_ISSUER,
                           audience=settings.JWT_AUDIENCE, algorithms=['HS256'])

                try:
                    api_key_record = APIKey.objects.get(
                        api_key=api_key, expire_at__gt=timezone.now())
                    request.middleware_api_key = api_key_record
                    request.middleware_institute = api_key_record.institute

                    success = True
                except:
                    message = "Authorization failed. Cannot find an APIKey record."
                    success = False
            except:
                message = "Authorization failed. Cannot decode the api_key."
                success = False

        if success:
            return

        if not self.optional_authentication:
            return MyResponse(request, {'status': 'error', 'message': message}, status=status.HTTP_401_UNAUTHORIZED)

        request.middleware_token_record = None
        request.middleware_user = None
        request.middleware_api_key = None
        request.middleware_institute = None
