# -*- coding: utf-8 -*-
"""
Django Permission System for Accounts App

This module provides a comprehensive permission system for the accounts app
with decorators, mixins, and utility functions for checking user permissions.
"""

from functools import wraps
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.http import JsonResponse
from django.shortcuts import redirect
from django.contrib import messages
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator


class PermissionRequiredMixin(LoginRequiredMixin):
    """
    Mixin that checks if user has required permissions.
    Can be used with class-based views.
    """
    permission_required = None
    permission_denied_message = "You don't have permission to access this page."
    
    def dispatch(self, request, *args, **kwargs):
        if not self.has_permission():
            if request.is_ajax():
                return JsonResponse({
                    'success': False,
                    'message': self.permission_denied_message
                }, status=403)
            else:
                messages.error(request, self.permission_denied_message)
                return redirect('core:dashboard')
        return super().dispatch(request, *args, **kwargs)
    
    def has_permission(self):
        """Check if user has required permissions."""
        if not self.permission_required:
            return True
        
        if isinstance(self.permission_required, str):
            permissions = [self.permission_required]
        else:
            permissions = self.permission_required
        
        return self.request.user.has_perms(permissions)


def permission_required(permission_codename, login_url=None, raise_exception=False):
    """
    Decorator for views that checks whether a user has permission to access the view.
    
    Args:
        permission_codename: String or list of permission codenames to check
        login_url: URL to redirect to if user is not authenticated
        raise_exception: Whether to raise PermissionDenied exception
    """
    def decorator(view_func):
        @wraps(view_func)
        @login_required(login_url=login_url)
        def _wrapped_view(request, *args, **kwargs):
            if isinstance(permission_codename, str):
                permissions = [permission_codename]
            else:
                permissions = permission_codename
            
            if not request.user.has_perms(permissions):
                if raise_exception:
                    raise PermissionDenied
                
                if request.is_ajax():
                    return JsonResponse({
                        'success': False,
                        'message': "You don't have permission to perform this action."
                    }, status=403)
                else:
                    messages.error(request, "You don't have permission to perform this action.")
                    return redirect('core:dashboard')
            
            return view_func(request, *args, **kwargs)
        return _wrapped_view
    return decorator


def ajax_permission_required(permission_codename):
    """
    Decorator specifically for AJAX views that checks permissions.
    """
    def decorator(view_func):
        @wraps(view_func)
        @login_required
        def _wrapped_view(request, *args, **kwargs):
            if isinstance(permission_codename, str):
                permissions = [permission_codename]
            else:
                permissions = permission_codename
            
            if not request.user.has_perms(permissions):
                return JsonResponse({
                    'success': False,
                    'message': "You don't have permission to perform this action."
                }, status=403)
            
            return view_func(request, *args, **kwargs)
        return _wrapped_view
    return decorator


def user_has_permission(user, permission_codename):
    """
    Utility function to check if a user has specific permission.
    
    Args:
        user: User instance
        permission_codename: String or list of permission codenames
    
    Returns:
        Boolean indicating if user has permission
    """
    if isinstance(permission_codename, str):
        permissions = [permission_codename]
    else:
        permissions = permission_codename
    
    return user.has_perms(permissions)


def get_user_permissions(user):
    """
    Get all permissions for a user including role-based permissions.
    
    Args:
        user: User instance
    
    Returns:
        QuerySet of permissions
    """
    from django.contrib.auth.models import Permission
    from .models import UserRole
    
    # Get direct user permissions
    user_permissions = user.user_permissions.all()
    
    # Get permissions from roles
    role_permissions = Permission.objects.filter(
        role__userrole__user=user,
        role__userrole__is_active=True
    ).distinct()
    
    # Combine permissions
    all_permissions = user_permissions.union(role_permissions)
    
    return all_permissions


class UserManagementPermissions:
    """Permission constants for user management."""
    
    # User permissions
    CAN_VIEW_USERS = 'accounts.view_user'
    CAN_ADD_USERS = 'accounts.add_user'
    CAN_CHANGE_USERS = 'accounts.change_user'
    CAN_DELETE_USERS = 'accounts.delete_user'
    
    # Role permissions
    CAN_VIEW_ROLES = 'accounts.view_role'
    CAN_ADD_ROLES = 'accounts.add_role'
    CAN_CHANGE_ROLES = 'accounts.change_role'
    CAN_DELETE_ROLES = 'accounts.delete_role'
    
    # Department permissions
    CAN_VIEW_DEPARTMENTS = 'accounts.view_department'
    CAN_ADD_DEPARTMENTS = 'accounts.add_department'
    CAN_CHANGE_DEPARTMENTS = 'accounts.change_department'
    CAN_DELETE_DEPARTMENTS = 'accounts.delete_department'
    
    # Permission permissions
    CAN_VIEW_PERMISSIONS = 'auth.view_permission'
    CAN_ADD_PERMISSIONS = 'auth.add_permission'
    CAN_CHANGE_PERMISSIONS = 'auth.change_permission'
    CAN_DELETE_PERMISSIONS = 'auth.delete_permission'
    
    # User role assignment permissions
    CAN_ASSIGN_ROLES = 'accounts.add_userrole'
    CAN_REVOKE_ROLES = 'accounts.delete_userrole'
    
    # Profile permissions
    CAN_VIEW_PROFILES = 'accounts.view_profile'
    CAN_CHANGE_PROFILES = 'accounts.change_profile'
    
    # Activity permissions
    CAN_VIEW_ACTIVITIES = 'activities.view_activity'
    
    # Session permissions
    CAN_VIEW_SESSIONS = 'accounts.view_usersession'
    CAN_TERMINATE_SESSIONS = 'accounts.delete_usersession'


def create_default_permissions():
    """
    Create default permissions for the accounts app.
    This should be called during app initialization.
    """
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    from .models import User, Role, Department, UserRole, Profile, UserSession
    
    # Custom permissions that don't exist by default
    custom_permissions = [
        # User management
        ('can_manage_users', 'Can manage all users'),
        ('can_view_user_details', 'Can view user details'),
        ('can_export_users', 'Can export user data'),
        
        # Role management
        ('can_assign_roles', 'Can assign roles to users'),
        ('can_manage_permissions', 'Can manage permissions'),
        
        # Department management
        ('can_manage_departments', 'Can manage departments'),
        
        # Profile management
        ('can_view_all_profiles', 'Can view all user profiles'),
        ('can_manage_profiles', 'Can manage user profiles'),
        
        # Session management
        ('can_view_all_sessions', 'Can view all user sessions'),
        ('can_terminate_sessions', 'Can terminate user sessions'),
        
        # Activity management
        ('can_view_all_activities', 'Can view all user activities'),
    ]
    
    # Create custom permissions
    for codename, name in custom_permissions:
        content_type = ContentType.objects.get_for_model(User)
        permission, created = Permission.objects.get_or_create(
            codename=codename,
            name=name,
            content_type=content_type
        )
        if created:
            print(f"Created permission: {codename}")


def setup_default_roles():
    """
    Set up default roles with appropriate permissions.
    """
    from django.contrib.auth.models import Permission
    from .models import Role
    
    # Define default roles and their permissions
    default_roles = {
        'super_admin': {
            'name': 'Super Administrator',
            'description': 'Has full access to all system features',
            'permissions': [
                'accounts.add_user', 'accounts.change_user', 'accounts.delete_user', 'accounts.view_user',
                'accounts.add_role', 'accounts.change_role', 'accounts.delete_role', 'accounts.view_role',
                'accounts.add_department', 'accounts.change_department', 'accounts.delete_department', 'accounts.view_department',
                'accounts.add_userrole', 'accounts.delete_userrole', 'accounts.view_userrole',
                'accounts.add_profile', 'accounts.change_profile', 'accounts.view_profile',
                'accounts.add_usersession', 'accounts.change_usersession', 'accounts.delete_usersession', 'accounts.view_usersession',
                'accounts.can_manage_users', 'accounts.can_assign_roles', 'accounts.can_manage_permissions',
                'accounts.can_view_all_profiles', 'accounts.can_view_all_sessions', 'accounts.can_terminate_sessions',
                'accounts.can_view_all_activities',
            ]
        },
        'admin': {
            'name': 'Administrator',
            'description': 'Has access to user and role management',
            'permissions': [
                'accounts.add_user', 'accounts.change_user', 'accounts.view_user',
                'accounts.view_role', 'accounts.add_userrole', 'accounts.delete_userrole',
                'accounts.view_department', 'accounts.change_profile', 'accounts.view_profile',
                'accounts.can_manage_users', 'accounts.can_assign_roles',
                'accounts.can_view_all_profiles', 'accounts.can_view_all_sessions',
            ]
        },
        'manager': {
            'name': 'Manager',
            'description': 'Has access to department and user management',
            'permissions': [
                'accounts.view_user', 'accounts.view_role', 'accounts.view_department',
                'accounts.view_profile', 'accounts.can_view_user_details',
            ]
        },
        'user': {
            'name': 'Regular User',
            'description': 'Basic user permissions',
            'permissions': [
                'accounts.view_profile', 'accounts.change_profile',
            ]
        }
    }
    
    for role_code, role_data in default_roles.items():
        role, created = Role.objects.get_or_create(
            code=role_code,
            defaults={
                'name': role_data['name'],
                'description': role_data['description'],
                'role_type': 'system',
                'level': 1 if role_code == 'super_admin' else 2 if role_code == 'admin' else 3 if role_code == 'manager' else 4,
                'is_active': True,
                'is_default': role_code == 'user'
            }
        )
        
        if created:
            print(f"Created role: {role_code}")
            
            # Add permissions to role
            permissions = Permission.objects.filter(codename__in=[
                perm.split('.')[-1] for perm in role_data['permissions']
            ])
            role.permissions.set(permissions)
            print(f"Added {permissions.count()} permissions to {role_code}")


def has_user_management_permission(user):
    """Check if user has any user management permissions."""
    return user.has_perms([
        UserManagementPermissions.CAN_VIEW_USERS,
        UserManagementPermissions.CAN_ADD_USERS,
        UserManagementPermissions.CAN_CHANGE_USERS,
    ])


def has_role_management_permission(user):
    """Check if user has any role management permissions."""
    return user.has_perms([
        UserManagementPermissions.CAN_VIEW_ROLES,
        UserManagementPermissions.CAN_ADD_ROLES,
        UserManagementPermissions.CAN_CHANGE_ROLES,
    ])


def has_department_management_permission(user):
    """Check if user has any department management permissions."""
    return user.has_perms([
        UserManagementPermissions.CAN_VIEW_DEPARTMENTS,
        UserManagementPermissions.CAN_ADD_DEPARTMENTS,
        UserManagementPermissions.CAN_CHANGE_DEPARTMENTS,
    ])
