from rest_framework import permissions


class IsOwner(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj.user == request.user


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


# noinspection PyProtectedMember,PyUnresolvedReferences
class EvibesPermission(permissions.BasePermission):
    ACTION_PERM_MAP = {
        "retrieve": "view",
        "list": "view",
        "create": "add",
        "update": "change",
        "partial_update": "change",
        "destroy": "delete",
    }

    USER_SCOPED_ACTIONS = {
        "list",
        "retrieve",
        "buy",
        "buy_unregistered",
        "current",
        "add_order_product",
        "remove_order_product",
        "bulk_add_order_products",
        "bulk_remove_order_products",
        "add_wishlist_product",
        "remove_wishlist_product",
        "bulk_add_wishlist_products",
        "bulk_remove_wishlist_products",
        "autocomplete",
    }

    def has_permission(self, request, view):
        action = view.action
        model = view.queryset.model
        app_label = model._meta.app_label
        model_name = model._meta.model_name

        if view.additional.get(action) == "ALLOW":
            return True

        if action == "create" and view.additional.get("create") == "ALLOW":
            return True

        if action == "retrieve" and view.additional.get("retrieve") == "ALLOW":
            return True

        if action in self.USER_SCOPED_ACTIONS:
            return True

        perm_prefix = self.ACTION_PERM_MAP.get(action)
        if perm_prefix and request.user.has_perm(f"{app_label}.{perm_prefix}_{model_name}"):
            return True

        return bool(action in ("list", "retrieve") and getattr(model, "is_publicly_visible", False))

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

        if hasattr(obj, "user"):
            if obj.user == request.user:
                return True
            app_label = obj._meta.app_label
            model_name = obj._meta.model_name
            action = view.action
            perm_prefix = self.ACTION_PERM_MAP.get(action)
            return bool(perm_prefix and request.user.has_perm(f"{app_label}.{perm_prefix}_{model_name}"))

        perm_prefix = self.ACTION_PERM_MAP.get(view.action)
        return bool(
            perm_prefix
            and request.user.has_perm(
                f"{view.queryset.model._meta.app_label}.{perm_prefix}_{view.queryset.model._meta.model_name}"
            )
        )

    def has_queryset_permission(self, request, view, queryset):
        model = view.queryset.model
        app_label = model._meta.app_label
        model_name = model._meta.model_name

        if hasattr(model, "user"):
            if view.action in self.USER_SCOPED_ACTIONS:
                return queryset.filter(user=request.user)
            if view.action in ("list", "retrieve"):
                if request.user.has_perm(f"{app_label}.view_{model_name}"):
                    return queryset
                return queryset.none()

            base = queryset.filter(is_active=True, user=request.user)
            if request.user.has_perm(f"{app_label}.{self.ACTION_PERM_MAP.get(view.action)}_{model_name}"):
                return queryset.filter(is_active=True)
            return base

        if view.action in ("list", "retrieve"):
            if request.user.has_perm(f"{app_label}.view_{model_name}"):
                if request.user.is_staff:
                    return queryset
                return queryset.filter(is_active=True)
            return queryset.none()

        base = queryset.filter(is_active=True)
        match view.action:
            case "update" | "partial_update":
                if request.user.has_perm(f"{app_label}.change_{model_name}"):
                    return base
            case "destroy":
                if request.user.has_perm(f"{app_label}.delete_{model_name}"):
                    return base

        return queryset.none()
