
#  ویوست ها و توابعی که برای ایجاد سطج دستزسی جدید در سیستم استفاده میشوند


from rest_framework.permissions import BasePermission, DjangoModelPermissions
# from django.utils.datetime_safe import datetime
from authentication.models import UserProfile
from django.contrib.auth.models import Group
from datetime import timedelta, datetime
from rest_framework import permissions
from django.utils import timezone


class IsAuthenticatedOrCreate(permissions.IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'POST':
            return True
        return super(IsAuthenticatedOrCreate, self).has_permission(request, view)


class IsOwner(permissions.BasePermission):
    message = "Not an owner."

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return request.user == obj.created_by


class AuthorOrReadOnly(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.is_authenticated:
            return True
        return False

    def has_object_permission(self, request, view, obj):
        if obj.author == request.user:
            return True
        return False


class AuthenticatedOnly(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.user.is_authenticated:
            return True
        return False


class AuthorAllStaffAllButEditOrReadOnly(permissions.BasePermission):
    edit_methods = ("PUT", "PATCH")

    def has_permission(self, request, view):
        if request.user.is_authenticated:
            return True

    def has_object_permission(self, request, view, obj):
        if request.user.is_superuser:
            return True

        if request.method in permissions.SAFE_METHODS:
            return True

        if obj.author == request.user:
            return True

        if request.user.is_staff and request.method not in self.edit_methods:
            return True

        return False


class ExpiredObjectSuperuserOnly(permissions.BasePermission):
    message = "This object is expired."  # custom error message

    def object_expired(self, obj):
        expired_on = timezone.make_aware(datetime.now() - timedelta(minutes=10))
        return obj.created < expired_on

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

        if self.object_expired(obj) and not request.user.is_superuser:
            return False
        else:
            return True


class IsStaff(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.is_staff:
            return True
        return False

    def has_object_permission(self, request, view, obj):
        if request.user.is_staff:
            return True
        return False


class IsOwner2(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.is_authenticated:
            return True
        return False

    def has_object_permission(self, request, view, obj):
        if obj.author == request.user:
            return True
        return False


class IsFinancesMember(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Finances").exists():
            return True


class IsCustomer(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Customer").exists():
            return True


class IsOperator(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Operator").exists():
            return True


class IsSaler(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Saler").exists():
            return True


class IsSupervisor(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Supervisor").exists():
            return True


class IsStorekeeper(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Storekeeper").exists():
            return True


class IsDeliveryMember(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Delivery").exists():
            return True


class IsAdminMember(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="Admin").exists():
            return True


class IsChatRoomOperator(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="ChatRoomOperator").exists():
            return True


class IsInformationOperator(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="InformationOperator").exists():
            return True


class IsFinanceUnitOperator(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="FinancialUnitOperator").exists():
            return True


class IsFinanceUnitAdmin(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.user.groups.filter(name="FinancialUnitAdmin").exists():
            return True


class IsSuperUser(BasePermission):

    def has_permission(self, request, view):
        return request.user and request.user.is_superuser


class CityOperator(BasePermission):

    def has_permission(self, request, view):
        if UserProfile.objects.filter(user__exact=request.user, role__name__exact="CityOperator").exists():
            return True
        else:
            return False


class ProvinceOperator(BasePermission):

    def has_permission(self, request, view):
        if UserProfile.objects.filter(user__exact=request.user, role__name__exact="ProvinceOperator").exists():
            return True


class Poultry(BasePermission):

    def has_permission(self, request, view):
        if UserProfile.objects.filter(user__exact=request.user, role__exact="Poultry").exists():
            return True


class KillHouseOperator(BasePermission):

    def has_permission(self, request, view):
        if UserProfile.objects.filter(user__exact=request.user, role__exact="KillHouseOperator").exists():
            return True


class OwnerOrModelPermission(DjangoModelPermissions):

    def __same_user(self, obj, request):
        from django.contrib.auth.models import User
        return isinstance(obj, User) and obj.id == request.user.id

    def __is_owner(self, obj, request):
        return hasattr(obj, 'owner') and obj.owner is not None and self.__same_user(obj.owner, request)

    def has_permission(self, request, view):
        return request.user.is_superuser or DjangoModelPermissions().has_permission(request, view)

    def has_object_permission(self, request, view, obj):
        return request.user.is_superuser or self.__same_user(
            obj, request) or self.__is_owner(
            obj, request) or DjangoModelPermissions().has_object_permission(request, view, obj)


class PaymentRequiredPermission(DjangoModelPermissions):
    def can_operate(self, request):
        return request.user.has_paid()

    def has_permission(self, request, view):
        return self.can_operate(request)

    def has_object_permission(self, request, view, obj):
        return self.can_operate(request)


class IsUser(BasePermission):
    def has_permission(self, request, view):
        return request.user and request.user.is_superuser

    def has_object_permission(self, request, view, obj):
        return request.user.is_superuser or obj.user.id == request.user.id


class APIPermission(permissions.BasePermission):
    message = 'Only API user can access APIs'

    group_name = "api"

    def has_permission(self, request, view):
        try:
            group = request.user.groups.get(name=self.group_name)
        except Group.DoesNotExist:
            self.message = "Permission denied, user group '{}' does not exists".format(self.group_name)
            return False
        return group.name == self.group_name


def _is_in_group(user, group_name):
    """
    Takes a user and a group name, and returns `True` if the user is in that group.
    """
    try:
        return Group.objects.get(name=group_name).user_set.filter(id=user.id).exists()
    except Group.DoesNotExist:
        return None


def _has_group_permission(user, required_groups):
    return any([_is_in_group(user, group_name) for group_name in required_groups])


class IsLoggedInUserOrAdmin(permissions.BasePermission):
    # group_name for super admin
    required_groups = ['admin']

    def has_object_permission(self, request, view, obj):
        has_group_permission = _has_group_permission(request.user, self.required_groups)
        if self.required_groups is None:
            return False
        return obj == request.user or has_group_permission


class IsAdminUser(permissions.BasePermission):
    # group_name for super admin
    required_groups = ['admin']

    def has_permission(self, request, view):
        has_group_permission = _has_group_permission(request.user, self.required_groups)
        return request.user and has_group_permission

    def has_object_permission(self, request, view, obj):
        has_group_permission = _has_group_permission(request.user, self.required_groups)
        return request.user and has_group_permission


class IsAdminOrAnonymousUser(permissions.BasePermission):
    required_groups = ['admin', 'anonymous']

    def has_permission(self, request, view):
        has_group_permission = _has_group_permission(request.user, self.required_groups)
        return request.user and has_group_permission
