"""Base project permissions."""

from django.core.cache import cache

# Django
from django.utils.translation import gettext_lazy as _

# Django REST Framework
from rest_framework.exceptions import NotAuthenticated
from rest_framework.permissions import BasePermission


class HasModelPermissions(BasePermission):
    """Allow access only to objects owned by the requesting user."""

    actions = {
        "retrieve": "view",
        "list": "view",
        "update": "change",
        "partial_update": "change",
        "create": "add",
        "delete": "delete",
        "init": "update",
    }

    def __init__(self, app_label, model):
        """
        Initializes the permission class with the app label of the model
        and an optional permission base string (defaults to app label).

        Args:
            app_label (str): The app label of the model involved in the API request.
            model (str): model involved in the API request.
        """
        self.app_label = app_label
        self.model = model

    def has_permission(self, request, view):
        """
        Checks if the user has the necessary permission for the requested action
        based on the view's action and the permission base string.

        Args:
            request (Request): The incoming HTTP request object.
            view (APIView): The DRF view object handling the request.

        Returns:
            bool: True if the user has the permission, False otherwise.
        """

        # Check for superuser access
        if request.user.is_superuser:
            return True

        # Access control based on view action and permission base
        action = self.actions[view.action]
        permission_codename = f"{self.app_label}.{action}_{self.model}"

        return request.user.has_perm(permission_codename)


class CustomIsAuthenticated(BasePermission):
    """
    A permission class that always denies access and raises a NotAuthenticated exception.
    """

    def has_permission(self, request, view):
        if not bool(request.user.is_authenticated):
            raise NotAuthenticated()

        return True


class IsObjectOwner(BasePermission):
    """Allow access only to objects owned by the requesting user."""

    def has_object_permission(self, request, view, obj):
        """Check obj and user are the same."""
        return request.user == obj.user


def get_object_permissions(permissions_list):
    permissions = {}
    for permission in permissions_list:
        action, content_type_model = permission.codename.split("_", 1)

        if content_type_model not in permissions:
            permissions[content_type_model] = {
                "id": permission.content_type_id,
                "name": _(content_type_model),
                "key": content_type_model,
                "view": False,
                "create": False,
                "edit": False,
                "delete": False,
            }

        if action == "view":
            permissions[content_type_model]["view"] = True
        elif action == "add":
            permissions[content_type_model]["create"] = True
        elif action == "change":
            permissions[content_type_model]["edit"] = True
        elif action == "delete":
            permissions[content_type_model]["delete"] = True

    return list(permissions.values())


class IsAuthenticatedDevice(BasePermission):
    """
    Allow access only to authenticated devices
    """

    def has_permission(self, request, view):
        return bool(request.user and hasattr(request, "device"))


class IsAccessPointDevice(BasePermission):
    """Allow access only to devices belonging to an access point"""

    def has_permission(self, request, view):
        if request.user and hasattr(request, "device"):
            return request.device.access_point


class LocalIPPermission(BasePermission):
    def has_permission(self, request, view):
        client_ip = self.get_client_ip(request)
        allowed_ips = cache.get("local_ips", [])

        return client_ip in allowed_ips

    def get_client_ip(self, request):
        ip_headers = [
            "HTTP_X_CLIENT_ID",
        ]

        for header in ip_headers:
            ip = request.META.get(header)
            if ip:
                # Si el encabezado contiene múltiples IPs, toma la primera
                return ip.split(",")[0].strip()

        return None
