from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.forms import ValidationError

from rest_framework import exceptions
from rest_framework.permissions import DjangoObjectPermissions

from access.mixin import OrganizationMixin

from core import exceptions as centurion_exceptions



class OrganizationPermissionAPI(DjangoObjectPermissions, OrganizationMixin):
    """checking organization membership"""

    def has_permission(self, request, view):

        # if view.kwargs.get('pk', None):

        #     if(
        #         str(type(view.get_object()).__name__).lower() == 'organization'
        #     ):

        #         if view.get_object().manager == request.user:

        #             return True

        return self.permission_check(request, view)


    def has_object_permission(self, request, view, obj):

        # if view.kwargs.get('pk', None):

        #     if(
        #         str(type(obj).__name__).lower() == 'organization'
        #     ):

        #         if obj.manager == request.user:

        #             return True

        return self.permission_check(request, view)


    def permission_check(self, request, view, obj=None) -> bool:

        if request.user.is_anonymous:

            return False

        try:

            self.request = request

            method = self.request._request.method.lower()

            if method.upper() not in view.allowed_methods:

                view.http_method_not_allowed(request._request)

            if request.user.is_authenticated and method == 'options':

                return True

            if hasattr(view, 'get_queryset'):

                queryset  = view.get_queryset()

                self.obj = queryset.model

            elif hasattr(view, 'queryset'):

                if view.queryset.model._meta:

                    self.obj = view.queryset.model

            object_organization = None

            if method == 'get':

                action = 'view'
            
            elif method == 'post':

                action = 'add'

                if 'organization' in request.data:

                    serializer = None

                    try:    # Method throws exception if not overridden

                        serializer = view.get_serializer_class()

                    except Exception as e:

                        serializer = None

                    try:    # Method throws exception if not overridden

                        serializer = view.get_serializer()

                    except Exception as e:

                        serializer = None


                    if 'organization' not in getattr(serializer.Meta, 'read_only_fields', []):

                        if not request.data['organization']:

                            raise centurion_exceptions.ValidationError('you must provide an organization')

                        object_organization = int(request.data['organization'])


            elif method == 'patch':

                action = 'change'

            elif method == 'put':

                action = 'change'

            elif method == 'delete':

                action = 'delete'

            else:

                action = 'view'

            if hasattr(self, 'obj'):
                
                permission = self.obj._meta.app_label + '.' + action + '_' + self.obj._meta.model_name

                self.permission_required = [ permission ]

            if hasattr(view, 'get_dynamic_permissions'):

                self.permission_required = view.get_dynamic_permissions()


            if view:
                if 'organization_id' in view.kwargs:

                    if view.kwargs['organization_id']:

                        object_organization = view.kwargs['organization_id']

                if object_organization is None and 'pk' in view.kwargs:

                    try:

                        self.obj = view.queryset.get(pk=view.kwargs['pk'])    # Here

                    except ObjectDoesNotExist:

                        return False


                if object_organization is None and getattr(view, 'parent_model', None):

                    parent_model = view.parent_model.objects.get(pk=view.kwargs[view.parent_model_pk_kwarg])

                    object_organization = parent_model.organization.id


            if obj:

                if obj.get_organization():

                    object_organization = obj.get_organization().id

                    if hasattr(self.obj, 'is_global'):
                        
                        if obj.is_global:

                            object_organization = 0


                if 'pk' in view.kwargs:

                    if object_organization is None and view.queryset.model._meta.model_name == 'tenant' and view.kwargs['pk']:

                        object_organization = view.kwargs['pk']

                if object_organization is None:

                    try:

                        self.obj = view.queryset.get()

                    except ObjectDoesNotExist:

                        return False


            if hasattr(self, 'obj') and object_organization is None and 'pk' in view.kwargs:

                if self.obj.get_organization():

                    object_organization = self.obj.get_organization().id

                    if hasattr(self.obj, 'is_global'):

                        if self.obj.is_global:

                            object_organization = 0


            # ToDo: implement proper checking of listview as this if allows ALL.
            if 'pk' not in view.kwargs and method == 'get' and object_organization is None:

                return True

            if hasattr(self, 'default_organization'):
                object_organization = self.default_organization

            if method == 'post' and hasattr(self, 'default_organization'):

                if self.default_organization:

                    object_organization = self.default_organization.id

            if not self.has_organization_permission(object_organization) and not request.user.is_superuser:

                raise PermissionDenied('You are not part of this organization')

        except centurion_exceptions.MethodNotAllowed as e:

            raise centurion_exceptions.MethodNotAllowed( str(method).upper() )

        except Exception as e:

            return False

        return True
