"""
DRF Permission Classes — Custom permission classes for view protection.

Usage in ViewSets:
    from apps.core.permission.drf_permissions import HasPermission, HasModuleAccess

    class MyViewSet(ModelViewSet):
        permission_classes = [IsAuthenticated, HasModuleAccess]
        module_name = 'pm'
        
        # Per-action permissions:
        permission_map = {
            'list': 'pm.task.list',
            'retrieve': 'pm.task.read',
            'create': 'pm.task.create',
            'update': 'pm.task.update',
            'partial_update': 'pm.task.update',
            'destroy': 'pm.task.delete',
        }
"""
import logging

from rest_framework.permissions import BasePermission

logger = logging.getLogger('apps')


class HasPermission(BasePermission):
    """
    Check if user has the required permission for this action.
    
    The ViewSet must define `permission_map` dict mapping action → permission codename.
    If the action is not in the map, access is granted (fail-open for unmapped actions).
    
    For object-level checks, uses the full 5-layer evaluate_access pipeline.
    """
    
    def has_permission(self, request, view):
        if not request.user or not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        permission_map = getattr(view, 'permission_map', {})
        action = getattr(view, 'action', None)
        
        if not permission_map or not action:
            return True  # No permission map defined → fail-open
        
        codename = permission_map.get(action)
        if not codename:
            return True  # Action not in map → fail-open
        
        from .services import PermissionService
        return PermissionService.evaluate_access(
            user=request.user,
            permission_codename=codename,
            module=getattr(view, 'module_name', ''),
            request=request,
        )
    
    def has_object_permission(self, request, view, obj):
        if request.user.is_superuser:
            return True
        
        permission_map = getattr(view, 'permission_map', {})
        action = getattr(view, 'action', None)
        codename = permission_map.get(action) if permission_map and action else None
        
        if not codename:
            return True
        
        from .services import PermissionService
        return PermissionService.evaluate_access(
            user=request.user,
            permission_codename=codename,
            obj=obj,
            module=getattr(view, 'module_name', ''),
            request=request,
        )


class HasAnyPermission(BasePermission):
    """
    Check if user has ANY of the specified permissions.
    
    Usage:
        class MyView(APIView):
            permission_classes = [IsAuthenticated, HasAnyPermission]
            required_permissions = ['pm.task.create', 'pm.task.manage']
    """
    
    def has_permission(self, request, view):
        if not request.user or not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        required = getattr(view, 'required_permissions', [])
        if not required:
            return True
        
        from .services import PermissionService
        return PermissionService.has_any_permission(request.user, required)


class HasModuleAccess(BasePermission):
    """
    Check if user's tenant has access to the specified module.
    
    Usage:
        class MyViewSet(ModelViewSet):
            permission_classes = [IsAuthenticated, HasModuleAccess]
            module_name = 'pm'
    """
    
    def has_permission(self, request, view):
        if not request.user or not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        module_name = getattr(view, 'module_name', '')
        if not module_name:
            return True
        
        from .services import PermissionService
        return PermissionService.has_module_access(request.user, module_name)


class HasRole(BasePermission):
    """
    Check if user has a specific role.
    
    Usage:
        class AdminOnlyView(APIView):
            permission_classes = [IsAuthenticated, HasRole]
            required_role = 'admin'
    """
    
    def has_permission(self, request, view):
        if not request.user or not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        required_role = getattr(view, 'required_role', '')
        if not required_role:
            return True
        
        from .services import PermissionService
        return PermissionService.has_role(request.user, required_role)


class IsOwnerOrHasPermission(BasePermission):
    """
    Object-level: allow if user is owner, otherwise check permission.
    
    Usage:
        class MyViewSet(ModelViewSet):
            permission_classes = [IsAuthenticated, IsOwnerOrHasPermission]
            owner_field = 'created_by'  # Field on model that references owner
            permission_map = {...}
    """
    
    def has_object_permission(self, request, view, obj):
        if request.user.is_superuser:
            return True
        
        owner_field = getattr(view, 'owner_field', 'created_by')
        owner = getattr(obj, owner_field, None)
        
        if owner and hasattr(owner, 'pk') and owner.pk == request.user.pk:
            return True
        
        # Fall back to permission check
        permission_map = getattr(view, 'permission_map', {})
        action = getattr(view, 'action', None)
        codename = permission_map.get(action) if permission_map and action else None
        
        if not codename:
            return True
        
        from .services import PermissionService
        return PermissionService.evaluate_access(
            user=request.user,
            permission_codename=codename,
            obj=obj,
            module=getattr(view, 'module_name', ''),
            request=request,
        )
