from rest_framework.response import Response
from rest_framework import status
import json
from rest_framework.exceptions import ParseError
from functools import wraps
from rest_framework.authtoken.models import Token
from app.entities.models import User, Department, Company
from app.entities import enums
from django.db.models import Q


def error_safe(function):
    def wrap(request, *args, **kwargs):
        stat = status.HTTP_500_INTERNAL_SERVER_ERROR
        try:
            return function(request, *args, **kwargs)
        # except 'DoesNotExist' as ex:
        #     print('ddd')
        #     stat = status.HTTP_404_NOT_FOUND

        except Exception as ex:
            data = ''
            try:
                data = str(ex)
                print(f'ERROR: {data}')
            except Exception as ex2:
                pass
            return Response(data={"message": data},
                            status=stat)

    wrap.__doc__ = function.__doc__
    wrap.__name__ = function.__name__
    return wrap


class rms:

    # variables
    enums_super = enums.UserTypeEnum.SUPER_USER.value
    enums_OUA = enums.UserTypeEnum.OVERALL_USER_ADMIN.value
    enums_company = enums.UserTypeEnum.COMPANY_USER_ADMIN.value
    enums_department = enums.UserTypeEnum.DEPARTMENT_USER_ADMIN.value
    enums_user = enums.UserTypeEnum.USER.value
    access_error = "Logged user is not allowed to access this endpoint."
    department_error = 'Department should be same with the logged user'
    company_error = 'Company should be same with the logged user'

    def user(self):
        return self.request.user

    def user_type(self):
        return rms.user(self).user_type

    def superuser_create(self):
        if rms.user_type(self) != rms.enums_super:
            raise ParseError(rms.access_error)
        else:
            return True

    @staticmethod
    def user_create(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):
            if rms.user_type(self) == rms.enums_user:
                raise ParseError(
                    rms.access_error
                )
            elif rms.user_type(self) == rms.enums_department:
                if request.data['department'] != rms.user(self).department.code:
                    raise ParseError(
                        rms.department_error
                    )
            elif rms.user_type(self) == rms.enums_company:
                user_company = rms.user(self).department.company
                request_department = Department.objects.filter(
                    Q(code=request.data['department']) &
                    Q(company=user_company)
                )
                if not request_department:
                    raise ParseError(rms.company_error)

            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def reset_password(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):
            if rms.user_type(self) == rms.enums_user:
                raise ParseError(
                    rms.access_error
                )
            elif rms.user_type(self) == rms.enums_department:
                instance = self.get_object()
                if rms.user(self).department.code != instance.department.code:
                    raise ParseError(
                        rms.department_error
                    )
            elif rms.user_type(self) == rms.enums_company:
                user_company = rms.user(self).department.company
                request_department = Department.objects.filter(
                    Q(code=request.user.department.code) &
                    Q(company=user_company)
                )
                if not request_department:
                    raise ParseError(rms.company_error)

            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def company_crate(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):
            rms.superuser_create(self)
            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def department_crate(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):
            rms.superuser_create(self)
            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def application_crate(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):
            rms.superuser_create(self)
            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def module_crate(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):
            rms.superuser_create(self)
            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def company_list(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):

            if rms.user_type(self) == rms.enums_company or rms.user_type(self) == rms.enums_department:

                id = rms.user(self).department.company.id

                self.queryset = self.queryset.filter(
                    id=id
                )
            elif rms.user_type(self) == rms.enums_super:
                pass
            elif rms.user_type(self) == rms.enums_OUA:
                pass
            else:
                raise ParseError(
                    rms.access_error
                )

            return function(self, request, *args, **kwargs)
        return wrapper

    @staticmethod
    def department_list(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):

            if rms.user_type(self) == rms.enums_department:
                id = rms.user(self).department.id

                self.queryset = self.queryset.filter(
                    id=id
                )
            elif rms.user_type(self) == rms.enums_OUA:
                pass
            elif rms.user_type(self) == rms.enums_company:
                pass
            elif rms.user_type(self) == rms.enums_super:
                pass
            else:
                raise ParseError(
                    rms.access_error
                )

            return function(self, request, *args, **kwargs)
        return wrapper


    @staticmethod
    def user_list(function):
        @wraps(function)
        def wrapper(self, request, *args, **kwargs):

            if rms.user_type(self) == rms.enums_department:
                code = rms.user(self).department.code

                self.queryset = self.queryset.filter(
                    department=str(code)
                )

            elif rms.user_type(self) == rms.enums_company:
                code = rms.user(self).department.company.code
                self.queryset = self.queryset.filter(
                    department__company=str(code)
                )
            elif rms.user_type(self) == rms.enums_super:
                pass
            elif rms.user_type(self) == rms.enums_OUA:
                pass
            else:
                raise ParseError(
                    rms.access_error
                )

            return function(self, request, *args, **kwargs)
        return wrapper
