from django.contrib import auth
from django.contrib.auth.middleware import AuthenticationMiddleware
from django.forms.models import model_to_dict
from django.db.models import ForeignKey
from django.http import JsonResponse
from pydoc import locate

import base64
import json


class AutologinAuthenticationMiddleware(AuthenticationMiddleware):

    def process_request(self, request):
        if 'autologin' not in request.COOKIES:
            return
        if request.COOKIES['autologin'] == '':
            auth.logout(request)
            return
        autologin_cookie_value = base64.b64decode(request.COOKIES['autologin'])
        # Py3 uses a bytes string here, so we need to decode to utf-8
        autologin_cookie_value = autologin_cookie_value.decode('utf-8')
        username = autologin_cookie_value.split(':')[0]
        password = autologin_cookie_value.split(':')[1]
        user = auth.authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                auth.login(request, user)


class FactoryBoyMiddleware():

    def _foreign_key_to_model(self, FactoryBoyClass, factory_boy_args):
        if not hasattr(FactoryBoyClass, '_meta'):
            return
        if not hasattr(FactoryBoyClass._meta.model, '_meta'):
            return
        # iterate over all keys to find foreign keys
        for field in FactoryBoyClass._meta.model._meta.fields:
            if isinstance(field, ForeignKey):
                for key, value in factory_boy_args.items():
                    key_name = '{}__pk'.format(field.name)
                    if key == key_name:
                        RelModel = field.foreign_related_fields[0].model
                        del factory_boy_args[key_name]
                        new_key = key_name.replace('__pk', '')
                        factory_boy_args[new_key] = RelModel.objects.first()

    def process_request(self, request):
        model_name = request.GET.get('FACTORY_BOY_MODEL_PATH')
        if not model_name:
            return
        get_args = request.GET.get('FACTORY_BOY_ARGS')
        try:
            factory_boy_args = json.loads(get_args)
        except ValueError:
            factory_boy_args = {}
        FactoryBoyClass = locate(model_name)
        if not FactoryBoyClass:
            msg = 'Factory Boy class "{}" could not be found'
            return JsonResponse(
                {
                    'error': msg.format(model_name)
                },
                status=400
            )
        self._foreign_key_to_model(FactoryBoyClass, factory_boy_args)
        try:
            obj = FactoryBoyClass(**factory_boy_args)
        except:
            return JsonResponse(
                {
                    'error': 'FactoryBoyClass "{}" '.format(model_name) +
                    'could not be instantiated with args "{}"'.format(
                        factory_boy_args
                    )
                },
                status=400
            )
        obj_meta = getattr(obj, '_meta', None)
        if not obj_meta:
            return JsonResponse(
                {
                    'error': 'The FactoryBoyClass "{}" '.format(model_name) +
                    'instance does not seem to provide a _meta attribute. ' +
                    'Please check if the Factory Boy class inherits from ' +
                    'DjangoModelFactory'
                },
                status=400
            )
        return JsonResponse(model_to_dict(obj), status=201)


class QuerySetMiddleware():

    def process_request(self, request):
        model_name = request.GET.get('MODEL_PATH')
        if not model_name:
            return
        get_args = request.GET.get('QUERY_ARGS')
        try:
            query_args = json.loads(get_args)
        except (ValueError, TypeError):
            query_args = {}
        ModelClass = locate(model_name)
        if not ModelClass:
            msg = 'Class "{}" could not be found'
            return JsonResponse(
                {
                    'error': msg.format(model_name)
                },
                status=400
            )
        result = []
        if query_args:
            try:
                objects = [ModelClass.objects.get(**query_args)]
            except ModelClass.DoesNotExist:
                objects = []
        else:
            objects = ModelClass.objects.all()
        for obj in objects:
            result.append(
                model_to_dict(obj)
            )
        return JsonResponse(result, safe=False, status=200)

@@ -1075,32 +1075,313 @@
 yMiddleware():%0A%0A
+    def _get_foreign_key_fields(self, FactoryBoyClass):%0A        foreign_key_fields = %5B%5D%0A        for field in FactoryBoyClass._meta.model._meta.fields:%0A            if isinstance(field, ForeignKey):%0A                foreign_key_fields.append(field)%0A        return foreign_key_fields%0A%0A
     def _foreign
@@ -1598,74 +1598,50 @@
     
-# iterate over all keys to find 
+for field in self._get_
 foreign
- keys%0A        for 
+_key_
 field
- in 
+s(
 Fact
@@ -1655,78 +1655,8 @@
 lass
-._meta.model._meta.fields:%0A            if isinstance(field, ForeignKey
 ):%0A 
@@ -1662,28 +1662,24 @@
             
-    
 for key, val
@@ -1710,20 +1710,16 @@
 tems():%0A
-    
         
@@ -1781,20 +1781,16 @@
         
-    
 if key =
@@ -1821,20 +1821,16 @@
         
-    
 RelModel
@@ -1890,20 +1890,16 @@
         
-    
 del fact
@@ -1941,20 +1941,16 @@
         
-    
 new_key 
@@ -1980,20 +1980,16 @@
 k', '')%0A
-    
         

Factor out _get_foreign_key_fields.