# -*- coding: utf-8 -*-
"""
Adtlas Activities Permissions

This module contains custom permission classes for the activities app,
providing fine-grained access control for activity tracking, monitoring,
and management functionality.

Features:
    - Role-based access control
    - Object-level permissions
    - Activity viewing permissions
    - Activity management permissions
    - User-specific activity access
    - Admin and superuser overrides

Author: Adtlas Development Team
Version: 1.0.0
Last Updated: 2025-01-27
"""

from rest_framework import permissions
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _

from .models import Activity, ActivityCategory


class CanViewActivities(permissions.BasePermission):
    """
    Permission class for viewing activities.
    
    This permission allows users to view activities based on their role
    and specific permissions. Users can view their own activities by default,
    while viewing others' activities requires specific permissions.
    
    Rules:
        - Superusers: Can view all activities
        - Staff with 'view_activity' permission: Can view all activities
        - Regular users: Can only view their own activities
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to view activities.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to view activities.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check for specific permission
        if request.user.has_perm('activities.view_activity'):
            return True
        
        # Staff members with admin access
        if request.user.is_staff and request.user.has_perm('activities.view_activity'):
            return True
        
        # Regular users can view their own activities
        return True
    
    def has_object_permission(self, request, view, obj):
        """
        Check if user has permission to view a specific activity.
        
        Args:
            request: Django request object
            view: Django view object
            obj: Activity object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check for specific permission
        if request.user.has_perm('activities.view_activity'):
            return True
        
        # Users can view their own activities
        if obj.user == request.user:
            return True
        
        # Department managers can view their team's activities
        if hasattr(request.user, 'managed_departments'):
            user_departments = request.user.managed_departments.all()
            if obj.user and hasattr(obj.user, 'department'):
                if obj.user.department in user_departments:
                    return True
        
        return False


class CanManageActivities(permissions.BasePermission):
    """
    Permission class for managing activities.
    
    This permission allows users to create, update, and delete activities
    based on their role and specific permissions.
    
    Rules:
        - Superusers: Can manage all activities
        - Staff with 'add_activity', 'change_activity', 'delete_activity': Can manage activities
        - Regular users: Can create activities and manage their own
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to manage activities.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to manage activities.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check action-specific permissions
        if view.action == 'create':
            return (
                request.user.has_perm('activities.add_activity') or
                request.user.is_authenticated  # All authenticated users can log activities
            )
        
        elif view.action in ['update', 'partial_update']:
            return request.user.has_perm('activities.change_activity')
        
        elif view.action == 'destroy':
            return request.user.has_perm('activities.delete_activity')
        
        # Default to requiring change permission
        return request.user.has_perm('activities.change_activity')
    
    def has_object_permission(self, request, view, obj):
        """
        Check if user has permission to manage a specific activity.
        
        Args:
            request: Django request object
            view: Django view object
            obj: Activity object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check action-specific permissions
        if view.action in ['update', 'partial_update']:
            # Users can update their own activities or with permission
            return (
                request.user.has_perm('activities.change_activity') or
                obj.user == request.user
            )
        
        elif view.action == 'destroy':
            # Only users with delete permission or activity owners
            return (
                request.user.has_perm('activities.delete_activity') or
                (obj.user == request.user and request.user.has_perm('activities.delete_activity'))
            )
        
        # Default to requiring change permission
        return request.user.has_perm('activities.change_activity')


class CanViewActivityCategories(permissions.BasePermission):
    """
    Permission class for viewing activity categories.
    
    This permission allows users to view activity categories based on
    their authentication status and role.
    
    Rules:
        - All authenticated users: Can view active categories
        - Staff with permissions: Can view all categories including inactive
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to view activity categories.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to view activity categories.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # All authenticated users can view categories
        return True
    
    def has_object_permission(self, request, view, obj):
        """
        Check if user has permission to view a specific category.
        
        Args:
            request: Django request object
            view: Django view object
            obj: ActivityCategory object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Superusers and staff can view all categories
        if request.user.is_superuser or request.user.is_staff:
            return True
        
        # Regular users can only view active categories
        return obj.is_active


class CanManageActivityCategories(permissions.BasePermission):
    """
    Permission class for managing activity categories.
    
    This permission allows users to create, update, and delete activity
    categories based on their role and specific permissions.
    
    Rules:
        - Superusers: Can manage all categories
        - Staff with category permissions: Can manage categories
        - Regular users: No access
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to manage activity categories.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to manage activity categories.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check action-specific permissions
        if view.action == 'create':
            return request.user.has_perm('activities.add_activitycategory')
        
        elif view.action in ['update', 'partial_update']:
            return request.user.has_perm('activities.change_activitycategory')
        
        elif view.action == 'destroy':
            return request.user.has_perm('activities.delete_activitycategory')
        
        # Default to requiring change permission
        return request.user.has_perm('activities.change_activitycategory')


class CanViewActivityAnalytics(permissions.BasePermission):
    """
    Permission class for viewing activity analytics.
    
    This permission allows users to access activity analytics and
    reporting functionality based on their role and permissions.
    
    Rules:
        - Superusers: Can view all analytics
        - Staff with analytics permissions: Can view analytics
        - Managers: Can view their team's analytics
        - Regular users: Can view their own analytics
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to view activity analytics.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to view activity analytics.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check for analytics permission
        if request.user.has_perm('activities.view_activity_analytics'):
            return True
        
        # Staff members with appropriate permissions
        if request.user.is_staff and request.user.has_perm('activities.view_activity'):
            return True
        
        # Managers can view their team's analytics
        if hasattr(request.user, 'managed_departments') and request.user.managed_departments.exists():
            return True
        
        # Regular users can view their own analytics
        return True


class CanExportActivities(permissions.BasePermission):
    """
    Permission class for exporting activities.
    
    This permission allows users to export activity data based on
    their role and specific permissions.
    
    Rules:
        - Superusers: Can export all activities
        - Staff with export permissions: Can export activities
        - Managers: Can export their team's activities
        - Regular users: Can export their own activities
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to export activities.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to export activities.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check for export permission
        if request.user.has_perm('activities.export_activity'):
            return True
        
        # Staff members with appropriate permissions
        if request.user.is_staff and request.user.has_perm('activities.view_activity'):
            return True
        
        # Managers can export their team's activities
        if hasattr(request.user, 'managed_departments') and request.user.managed_departments.exists():
            return True
        
        # Regular users can export their own activities
        return True


class IsActivityOwnerOrReadOnly(permissions.BasePermission):
    """
    Permission class for activity ownership.
    
    This permission allows read access to all authenticated users
    but write access only to the activity owner or users with
    appropriate permissions.
    
    Rules:
        - Read access: All authenticated users (subject to other permissions)
        - Write access: Activity owner or users with change permissions
    """
    
    message = _("You can only modify your own activities.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission for the requested action.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Read permissions for authenticated users
        if request.method in permissions.SAFE_METHODS:
            return True
        
        # Write permissions require authentication
        return request.user.is_authenticated
    
    def has_object_permission(self, request, view, obj):
        """
        Check if user has permission for the specific object.
        
        Args:
            request: Django request object
            view: Django view object
            obj: Activity object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Read permissions for authenticated users
        if request.method in permissions.SAFE_METHODS:
            return True
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Users with change permission
        if request.user.has_perm('activities.change_activity'):
            return True
        
        # Activity owner can modify their own activities
        return obj.user == request.user


class CanAccessActivityDashboard(permissions.BasePermission):
    """
    Permission class for accessing activity dashboard.
    
    This permission controls access to the activity dashboard
    and monitoring interfaces.
    
    Rules:
        - Superusers: Full dashboard access
        - Staff with dashboard permissions: Dashboard access
        - Managers: Limited dashboard access for their teams
        - Regular users: Personal dashboard access
        - Anonymous users: No access
    """
    
    message = _("You do not have permission to access the activity dashboard.")
    
    def has_permission(self, request, view):
        """
        Check if user has permission to access the dashboard.
        
        Args:
            request: Django request object
            view: Django view object
        
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Anonymous users have no access
        if not request.user or not request.user.is_authenticated:
            return False
        
        # Superusers have full access
        if request.user.is_superuser:
            return True
        
        # Check for dashboard permission
        if request.user.has_perm('activities.view_activity_dashboard'):
            return True
        
        # Staff members with appropriate permissions
        if request.user.is_staff:
            return True
        
        # Managers can access dashboard for their teams
        if hasattr(request.user, 'managed_departments') and request.user.managed_departments.exists():
            return True
        
        # Regular users can access personal dashboard
        return True


def create_activity_permissions():
    """
    Create custom permissions for the activities app.
    
    This function creates additional permissions beyond the default
    Django model permissions for fine-grained access control.
    
    Returns:
        list: List of created permission objects
    """
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    
    # Get content types
    activity_ct = ContentType.objects.get_for_model(Activity)
    category_ct = ContentType.objects.get_for_model(ActivityCategory)
    
    # Define custom permissions
    custom_permissions = [
        # Activity permissions
        {
            'codename': 'view_activity_analytics',
            'name': 'Can view activity analytics',
            'content_type': activity_ct
        },
        {
            'codename': 'export_activity',
            'name': 'Can export activities',
            'content_type': activity_ct
        },
        {
            'codename': 'view_activity_dashboard',
            'name': 'Can view activity dashboard',
            'content_type': activity_ct
        },
        {
            'codename': 'manage_activity_retention',
            'name': 'Can manage activity retention policies',
            'content_type': activity_ct
        },
        {
            'codename': 'view_all_user_activities',
            'name': 'Can view all user activities',
            'content_type': activity_ct
        },
        
        # Category permissions
        {
            'codename': 'manage_activity_categories',
            'name': 'Can manage activity categories',
            'content_type': category_ct
        },
    ]
    
    created_permissions = []
    
    for perm_data in custom_permissions:
        permission, created = Permission.objects.get_or_create(
            codename=perm_data['codename'],
            content_type=perm_data['content_type'],
            defaults={'name': perm_data['name']}
        )
        
        if created:
            created_permissions.append(permission)
    
    return created_permissions


def assign_default_permissions():
    """
    Assign default permissions to user groups.
    
    This function assigns appropriate permissions to default
    user groups for the activities app.
    
    Returns:
        dict: Summary of assigned permissions
    """
    from django.contrib.auth.models import Group, Permission
    
    # Get or create groups
    admin_group, _ = Group.objects.get_or_create(name='Activity Administrators')
    manager_group, _ = Group.objects.get_or_create(name='Activity Managers')
    viewer_group, _ = Group.objects.get_or_create(name='Activity Viewers')
    
    # Get permissions
    activity_permissions = Permission.objects.filter(
        content_type__app_label='activities'
    )
    
    # Assign permissions to groups
    assignment_summary = {
        'admin_group': [],
        'manager_group': [],
        'viewer_group': []
    }
    
    # Admin group gets all permissions
    for perm in activity_permissions:
        admin_group.permissions.add(perm)
        assignment_summary['admin_group'].append(perm.codename)
    
    # Manager group gets view, add, change permissions
    manager_perms = activity_permissions.filter(
        codename__in=[
            'view_activity', 'add_activity', 'change_activity',
            'view_activitycategory', 'add_activitycategory', 'change_activitycategory',
            'view_activity_analytics', 'export_activity', 'view_activity_dashboard'
        ]
    )
    
    for perm in manager_perms:
        manager_group.permissions.add(perm)
        assignment_summary['manager_group'].append(perm.codename)
    
    # Viewer group gets only view permissions
    viewer_perms = activity_permissions.filter(
        codename__in=[
            'view_activity', 'view_activitycategory', 'view_activity_dashboard'
        ]
    )
    
    for perm in viewer_perms:
        viewer_group.permissions.add(perm)
        assignment_summary['viewer_group'].append(perm.codename)
    
    return assignment_summary