"""
Workflow Permissions.

Django REST Framework permission classes for workflow API.
"""
from rest_framework import permissions


class IsWorkflowAdmin(permissions.BasePermission):
    """
    Permission for workflow administrators.
    
    Users with this permission can:
    - Create/edit/delete process definitions
    - Deploy process definitions
    - View all process instances
    - Cancel any process instance
    - Reassign any task
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        # SuperAdmin and TenantAdmin have all permissions
        if request.user.is_superuser:
            return True
        
        # Check for workflow admin permission
        return request.user.has_perm('workflow.change_processdefinition')


class IsProcessDefinitionOwner(permissions.BasePermission):
    """
    Permission for process definition owners.
    
    Users who created a process definition can edit it (if draft).
    """
    
    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        # Check if user is the creator
        return obj.created_by == request.user


class CanDeployProcessDefinition(permissions.BasePermission):
    """
    Permission to deploy process definitions.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return request.user.has_perm('workflow.deploy_processdefinition')


class CanStartProcess(permissions.BasePermission):
    """
    Permission to start process instances.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return request.user.has_perm('workflow.start_processinstance')


class CanCancelProcess(permissions.BasePermission):
    """
    Permission to cancel process instances.
    
    Users can cancel their own process instances or need the cancel permission.
    """
    
    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        # User who started the process can cancel it
        if obj.started_by == request.user:
            return True
        
        return request.user.has_perm('workflow.cancel_processinstance')


class CanViewAllInstances(permissions.BasePermission):
    """
    Permission to view all process instances.
    
    Without this permission, users can only see instances they started.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return request.user.has_perm('workflow.view_all_instances')


class IsTaskParticipant(permissions.BasePermission):
    """
    Permission for task participants.
    
    Users can access a task if they are:
    - The assignee
    - A candidate user
    - In a candidate group
    - The process starter
    - A workflow admin
    """
    
    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        # Workflow admins can view all tasks
        if request.user.has_perm('workflow.view_all_tasks'):
            return True
        
        # Check if user is the assignee
        if obj.assignee == request.user:
            return True
        
        # Check if user is a candidate
        if obj.is_candidate(request.user):
            return True
        
        # Check if user started the process
        if obj.instance.started_by == request.user:
            return True
        
        return False


class CanClaimTask(permissions.BasePermission):
    """
    Permission to claim a task.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        return request.user.has_perm('workflow.claim_task') or request.user.is_superuser

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return obj.can_claim(request.user)


class CanCompleteTask(permissions.BasePermission):
    """
    Permission to complete a task.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        return request.user.has_perm('workflow.complete_task') or request.user.is_superuser

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return obj.can_complete(request.user)


class CanDelegateTask(permissions.BasePermission):
    """
    Permission to delegate a task.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        return request.user.has_perm('workflow.delegate_task') or request.user.is_superuser

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        # Only the assignee can delegate
        return obj.assignee == request.user


class CanReassignTask(permissions.BasePermission):
    """
    Permission to reassign a task (admin action).
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        return request.user.has_perm('workflow.reassign_task') or request.user.is_superuser


class CanViewAllTasks(permissions.BasePermission):
    """
    Permission to view all tasks.
    
    Without this permission, users can only see their own tasks.
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return request.user.has_perm('workflow.view_all_tasks')


class IsProcessInstanceOwner(permissions.BasePermission):
    """
    Permission based on process instance ownership.
    
    Users who started a process instance have access to it.
    """
    
    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        return obj.started_by == request.user


class TenantIsolationPermission(permissions.BasePermission):
    """
    Permission to ensure tenant isolation.
    
    Users can only access objects within their own tenant.
    """
    
    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        if request.user.is_superuser:
            return True
        
        # Check if object has tenant attribute
        if hasattr(obj, 'tenant'):
            return obj.tenant == request.user.tenant
        
        # For models without tenant (like TaskAssignment), check through relations
        if hasattr(obj, 'task'):
            return obj.task.tenant == request.user.tenant
        
        return True


# =============================================================================
# Combined Permission Classes
# =============================================================================

class ProcessDefinitionPermission(permissions.BasePermission):
    """
    Combined permission for process definition views.
    
    - List/Retrieve: Any authenticated user in the same tenant
    - Create: Workflow admin
    - Update: Workflow admin or owner (if draft)
    - Delete: Workflow admin or owner (if draft)
    - Deploy: Workflow admin with deploy permission
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        # Safe methods are allowed for authenticated users
        if request.method in permissions.SAFE_METHODS:
            return True
        
        # Write methods require workflow admin or owner
        if request.user.is_superuser:
            return True
        
        return request.user.has_perm('workflow.change_processdefinition')

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        # Tenant isolation
        if hasattr(obj, 'tenant') and obj.tenant != request.user.tenant:
            return False
        
        # Safe methods are allowed
        if request.method in permissions.SAFE_METHODS:
            return True
        
        if request.user.is_superuser:
            return True
        
        # Owner can edit draft definitions
        if obj.created_by == request.user and not obj.is_deployed:
            return True
        
        return request.user.has_perm('workflow.change_processdefinition')


class ProcessInstancePermission(permissions.BasePermission):
    """
    Combined permission for process instance views.
    
    - List: Users see their own instances or all if they have view_all_instances
    - Retrieve: Owner, task participant, or workflow admin
    - Create (Start): Users with start_processinstance permission
    - Cancel/Suspend/Resume: Owner or workflow admin
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        if request.method in permissions.SAFE_METHODS:
            return True
        
        if request.user.is_superuser:
            return True
        
        # Start action
        if view.action == 'start':
            return request.user.has_perm('workflow.start_processinstance')
        
        return True

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        # Tenant isolation
        if hasattr(obj, 'tenant') and obj.tenant != request.user.tenant:
            return False
        
        if request.user.is_superuser:
            return True
        
        # View all instances permission
        if request.user.has_perm('workflow.view_all_instances'):
            return True
        
        # Owner can always access their instance
        if obj.started_by == request.user:
            return True
        
        # Task participants can view the instance
        if obj.tasks.filter(
            assignments__user=request.user,
            assignments__is_active=True
        ).exists():
            return True
        
        return False


class TaskPermission(permissions.BasePermission):
    """
    Combined permission for task views.
    
    - List: Users see available tasks (assigned or candidate)
    - Retrieve: Task participant or workflow admin
    - Claim/Unclaim: Task participant
    - Complete: Assignee
    - Delegate: Assignee
    - Reassign: Workflow admin
    """
    
    def has_permission(self, request, view):
        if not request.user.is_authenticated:
            return False
        
        return True

    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        
        # Tenant isolation
        if hasattr(obj, 'tenant') and obj.tenant != request.user.tenant:
            return False
        
        if request.user.is_superuser:
            return True
        
        # View all tasks permission
        if request.user.has_perm('workflow.view_all_tasks'):
            return True
        
        # Safe methods: participants can view
        if request.method in permissions.SAFE_METHODS:
            if obj.assignee == request.user:
                return True
            if obj.is_candidate(request.user):
                return True
            if obj.instance.started_by == request.user:
                return True
            return False
        
        # Action-specific permissions
        if view.action == 'claim':
            return obj.can_claim(request.user)
        elif view.action == 'unclaim':
            return obj.assignee == request.user
        elif view.action == 'complete':
            return obj.can_complete(request.user)
        elif view.action == 'delegate':
            return obj.assignee == request.user
        elif view.action == 'reassign':
            return request.user.has_perm('workflow.reassign_task')
        
        return False
