"""
Moderation Permissions

This module contains custom permission classes for the moderation system,
providing role-based access control for moderation operations.

Each permission class includes an `as_guard()` class method that converts
the permission to an FSM guard function, enabling alignment between API
permissions and FSM transition checks.
"""

from collections.abc import Callable
from typing import Any

from django.contrib.auth import get_user_model
from rest_framework import permissions

User = get_user_model()


class PermissionGuardAdapter:
    """
    Adapter that wraps a DRF permission class as an FSM guard.

    This allows DRF permission classes to be used as conditions
    for FSM transitions, ensuring consistent authorization between
    API endpoints and state transitions.

    Example:
        guard = IsModeratorOrAdmin.as_guard()
        # Use in FSM transition conditions
        @transition(conditions=[guard])
        def approve(self, user=None):
            pass
    """

    def __init__(
        self,
        permission_class: type,
        error_message: str | None = None,
    ):
        """
        Initialize the guard adapter.

        Args:
            permission_class: The DRF permission class to adapt
            error_message: Custom error message on failure
        """
        self.permission_class = permission_class
        self._custom_error_message = error_message
        self._last_error_code: str | None = None

    @property
    def error_code(self) -> str | None:
        """Return the error code from the last failed check."""
        return self._last_error_code

    def __call__(self, instance: Any, user: Any = None) -> bool:
        """
        Check if the permission passes for the given user.

        Args:
            instance: Model instance being transitioned
            user: User attempting the transition

        Returns:
            True if the permission check passes
        """
        self._last_error_code = None

        if user is None:
            self._last_error_code = "NO_USER"
            return False

        # Create a mock request object for DRF permission check
        class MockRequest:
            def __init__(self, user):
                self.user = user
                self.data = {}
                self.method = "POST"

        mock_request = MockRequest(user)
        permission = self.permission_class()

        # Check permission
        if not permission.has_permission(mock_request, None):
            self._last_error_code = "PERMISSION_DENIED"
            return False

        # Check object permission if available
        if hasattr(permission, "has_object_permission"):  # noqa: SIM102
            if not permission.has_object_permission(mock_request, None, instance):
                self._last_error_code = "OBJECT_PERMISSION_DENIED"
                return False

        return True

    def get_error_message(self) -> str:
        """Return user-friendly error message."""
        if self._custom_error_message:
            return self._custom_error_message
        return f"Permission denied by {self.permission_class.__name__}"

    def get_required_roles(self) -> list:
        """Return list of roles that would satisfy this permission."""
        # Try to infer from permission class name
        name = self.permission_class.__name__
        if "Superuser" in name:
            return ["SUPERUSER"]
        elif "Admin" in name:
            return ["ADMIN", "SUPERUSER"]
        elif "Moderator" in name:
            return ["MODERATOR", "ADMIN", "SUPERUSER"]
        return ["USER", "MODERATOR", "ADMIN", "SUPERUSER"]


class GuardMixin:
    """
    Mixin that adds guard adapter functionality to DRF permission classes.
    """

    @classmethod
    def as_guard(cls, error_message: str | None = None) -> Callable:
        """
        Convert this permission class to an FSM guard function.

        Args:
            error_message: Optional custom error message

        Returns:
            Guard function compatible with FSM transition conditions

        Example:
            guard = IsModeratorOrAdmin.as_guard()

            # In transition definition
            @transition(conditions=[guard])
            def approve(self, user=None):
                pass
        """
        return PermissionGuardAdapter(cls, error_message=error_message)


class IsModerator(GuardMixin, permissions.BasePermission):
    """
    Permission that only allows moderators to access the view.

    Use `IsModerator.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has moderator role."""
        if not request.user or not request.user.is_authenticated:
            return False

        user_role = getattr(request.user, "role", "USER")
        return user_role == "MODERATOR"

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for moderators."""
        return self.has_permission(request, view)


class IsModeratorOrAdmin(GuardMixin, permissions.BasePermission):
    """
    Permission that allows moderators, admins, and superusers to access the view.

    Use `IsModeratorOrAdmin.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has moderator, admin, or superuser role."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers always have access
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")
        return user_role in ["MODERATOR", "ADMIN", "SUPERUSER"]

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for moderators and admins."""
        return self.has_permission(request, view)


class IsAdminOrSuperuser(GuardMixin, permissions.BasePermission):
    """
    Permission that only allows admins and superusers to access the view.

    Use `IsAdminOrSuperuser.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has admin or superuser role."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers always have access
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")
        return user_role in ["ADMIN", "SUPERUSER"]

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for admins and superusers."""
        return self.has_permission(request, view)


class CanViewModerationData(GuardMixin, permissions.BasePermission):
    """
    Permission that allows users to view moderation data based on their role.

    - Regular users can only view their own reports
    - Moderators and above can view all moderation data

    Use `CanViewModerationData.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated."""
        return request.user and request.user.is_authenticated

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for viewing moderation data."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers can view all data
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")

        # Moderators and above can view all data
        if user_role in ["MODERATOR", "ADMIN", "SUPERUSER"]:
            return True

        # Regular users can only view their own reports
        if hasattr(obj, "reported_by"):
            return obj.reported_by == request.user

        # For other objects, deny access to regular users
        return False


class CanModerateContent(GuardMixin, permissions.BasePermission):
    """
    Permission that allows users to moderate content based on their role.

    - Only moderators and above can moderate content
    - Includes additional checks for specific moderation actions

    Use `CanModerateContent.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has moderation privileges."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers always have access
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")
        return user_role in ["MODERATOR", "ADMIN", "SUPERUSER"]

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for content moderation."""
        if not self.has_permission(request, view):
            return False

        # Django superusers can do everything
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")

        # Superusers can do everything
        if user_role == "SUPERUSER":
            return True

        # Admins can moderate most content but may have some restrictions
        if user_role == "ADMIN":
            # Add any admin-specific restrictions here if needed
            return True

        # Moderators have basic moderation permissions
        if user_role == "MODERATOR":
            # Add any moderator-specific restrictions here if needed
            # For example, moderators might not be able to moderate admin actions
            if hasattr(obj, "moderator") and obj.moderator:
                moderator_role = getattr(obj.moderator, "role", "USER")
                if moderator_role in ["ADMIN", "SUPERUSER"]:
                    return False
            return True

        return False


class CanAssignModerationTasks(GuardMixin, permissions.BasePermission):
    """
    Permission that allows users to assign moderation tasks to others.

    - Moderators can assign tasks to themselves
    - Admins can assign tasks to moderators and themselves
    - Superusers can assign tasks to anyone

    Use `CanAssignModerationTasks.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has assignment privileges."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers always have access
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")
        return user_role in ["MODERATOR", "ADMIN", "SUPERUSER"]

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for task assignment."""
        if not self.has_permission(request, view):
            return False

        user_role = getattr(request.user, "role", "USER")

        # Superusers can assign to anyone
        if user_role == "SUPERUSER":
            return True

        # Admins can assign to moderators and themselves
        if user_role == "ADMIN":
            return True

        # Moderators can only assign to themselves
        if user_role == "MODERATOR":
            # Check if they're trying to assign to themselves
            assignee_id = request.data.get("moderator_id") or request.data.get("assigned_to")
            if assignee_id:
                return str(assignee_id) == str(request.user.id)
            return True

        return False


class CanPerformBulkOperations(GuardMixin, permissions.BasePermission):
    """
    Permission that allows users to perform bulk operations.

    - Only admins and superusers can perform bulk operations
    - Includes additional safety checks for destructive operations

    Use `CanPerformBulkOperations.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has bulk operation privileges."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers always have access
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")
        return user_role in ["ADMIN", "SUPERUSER"]

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for bulk operations."""
        if not self.has_permission(request, view):
            return False

        # Django superusers can perform all bulk operations
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")

        # Superusers can perform all bulk operations
        if user_role == "SUPERUSER":
            return True

        # Admins can perform most bulk operations
        if user_role == "ADMIN":
            # Add any admin-specific restrictions for bulk operations here
            # For example, admins might not be able to perform certain destructive operations
            operation_type = getattr(obj, "operation_type", None)
            if operation_type in ["DELETE_USERS", "PURGE_DATA"]:  # noqa: SIM103
                return False  # Only superusers can perform these operations
            return True

        return False


class IsOwnerOrModerator(GuardMixin, permissions.BasePermission):
    """
    Permission that allows object owners or moderators to access the view.

    - Users can access their own objects
    - Moderators and above can access any object

    Use `IsOwnerOrModerator.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated."""
        return request.user and request.user.is_authenticated

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for owners or moderators."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers can access any object
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")

        # Moderators and above can access any object
        if user_role in ["MODERATOR", "ADMIN", "SUPERUSER"]:
            return True

        # Check if user is the owner of the object
        if hasattr(obj, "reported_by"):
            return obj.reported_by == request.user
        elif hasattr(obj, "created_by"):
            return obj.created_by == request.user
        elif hasattr(obj, "user"):
            return obj.user == request.user

        return False


class CanManageUserRestrictions(GuardMixin, permissions.BasePermission):
    """
    Permission that allows users to manage user restrictions and moderation actions.

    - Moderators can create basic restrictions (warnings, temporary suspensions)
    - Admins can create more severe restrictions (longer suspensions, content removal)
    - Superusers can create any restriction including permanent bans

    Use `CanManageUserRestrictions.as_guard()` to get an FSM-compatible guard.
    """

    def has_permission(self, request, view):
        """Check if user is authenticated and has restriction management privileges."""
        if not request.user or not request.user.is_authenticated:
            return False

        # Django superusers always have access
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")
        return user_role in ["MODERATOR", "ADMIN", "SUPERUSER"]

    def has_object_permission(self, request, view, obj):
        """Check object-level permissions for managing user restrictions."""
        if not self.has_permission(request, view):
            return False

        # Django superusers can manage any restriction
        if getattr(request.user, "is_superuser", False):
            return True

        user_role = getattr(request.user, "role", "USER")

        # Superusers can manage any restriction
        if user_role == "SUPERUSER":
            return True

        # Get the action type from request data or object
        action_type = None
        if request.method in ["POST", "PUT", "PATCH"]:
            action_type = request.data.get("action_type")
        elif hasattr(obj, "action_type"):
            action_type = obj.action_type

        # Admins can manage most restrictions
        if user_role == "ADMIN":
            # Admins cannot create permanent bans
            return not (action_type == "USER_BAN" and request.data.get("duration_hours") is None)

        # Moderators can only manage basic restrictions
        if user_role == "MODERATOR":
            allowed_actions = ["WARNING", "CONTENT_REMOVAL", "USER_SUSPENSION"]
            if action_type not in allowed_actions:
                return False

            # Moderators can only create temporary suspensions (max 7 days)
            if action_type == "USER_SUSPENSION":
                duration_hours = request.data.get("duration_hours", 0)
                if duration_hours > 168:  # 7 days = 168 hours
                    return False

            return True

        return False
