"""
Decorators for audit logging integration
"""
from functools import wraps
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.core.exceptions import PermissionDenied
import logging
from .audit_service import audit_service
from .audit_models import SecurityEventSeverity

logger = logging.getLogger(__name__)


def audit_action(action=None, module=None, requires_permission=None, log_data_access=False):
    """
    Decorator to automatically log user actions with audit trail
    
    Args:
        action: Action name (defaults to view function name)
        module: Module name (defaults to app name)
        requires_permission: Permission required for this action
        log_data_access: Whether to log as data access event
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            # Determine action and module
            action_name = action or view_func.__name__
            module_name = module or getattr(view_func, '__module__', '').split('.')[-2] if '.' in getattr(view_func, '__module__', '') else 'unknown'
            
            # Check permission if required
            if requires_permission and request.user.is_authenticated:
                if not request.user.has_perm(requires_permission):
                    # Log permission denial
                    audit_service.log_permission_check(
                        user=request.user,
                        permission=requires_permission,
                        granted=False,
                        request=request,
                        module=module_name,
                        action=action_name
                    )
                    raise PermissionDenied(f"Permission required: {requires_permission}")
                else:
                    # Log successful permission check
                    audit_service.log_permission_check(
                        user=request.user,
                        permission=requires_permission,
                        granted=True,
                        request=request,
                        module=module_name,
                        action=action_name
                    )
            
            # Execute the view
            try:
                response = view_func(request, *args, **kwargs)
                
                # Log successful action
                if request.user.is_authenticated:
                    if log_data_access and 'pk' in kwargs:
                        # Log data access for specific object
                        audit_service.log_data_access(
                            user=request.user,
                            model_class=view_func.__name__,  # This could be improved with actual model
                            object_id=kwargs['pk'],
                            action=action_name,
                            request=request,
                            module=module_name
                        )
                    else:
                        # Log general action
                        audit_service.log_user_action(
                            user=request.user,
                            action=action_name,
                            module=module_name,
                            request=request,
                            description=f"Successfully executed {action_name}"
                        )
                
                return response
                
            except Exception as e:
                # Log failed action
                if request.user.is_authenticated:
                    audit_service.log_security_event(
                        user=request.user,
                        action=f"failed_{action_name}",
                        severity=SecurityEventSeverity.LOW,
                        description=f"Failed to execute {action_name}: {str(e)}",
                        request=request,
                        module=module_name,
                        exception_type=type(e).__name__
                    )
                raise
        
        return wrapper
    return decorator


def audit_permission_check(permission):
    """
    Decorator specifically for permission checking with audit logging
    """
    def decorator(view_func):
        @wraps(view_func)
        @login_required
        def wrapper(request, *args, **kwargs):
            # Check permission and log the attempt
            has_permission = request.user.has_perm(permission)
            
            # Log permission check
            audit_service.log_permission_check(
                user=request.user,
                permission=permission,
                granted=has_permission,
                request=request,
                module=getattr(view_func, '__module__', '').split('.')[-2] if '.' in getattr(view_func, '__module__', '') else 'unknown',
                action=view_func.__name__
            )
            
            if not has_permission:
                raise PermissionDenied(f"Permission required: {permission}")
            
            return view_func(request, *args, **kwargs)
        
        return wrapper
    return decorator


def audit_data_modification(model_class=None):
    """
    Decorator for views that modify data
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if not request.user.is_authenticated:
                return view_func(request, *args, **kwargs)
            
            # Determine action based on HTTP method
            method_actions = {
                'POST': 'create',
                'PUT': 'update',
                'PATCH': 'update',
                'DELETE': 'delete'
            }
            
            action = method_actions.get(request.method, 'modify')
            object_id = kwargs.get('pk') or kwargs.get('id')
            
            try:
                response = view_func(request, *args, **kwargs)
                
                # Log successful data modification
                if model_class:
                    audit_service.log_data_access(
                        user=request.user,
                        model_class=model_class,
                        object_id=object_id,
                        action=action,
                        request=request,
                        module=model_class.__name__.lower() if model_class else 'unknown'
                    )
                else:
                    audit_service.log_user_action(
                        user=request.user,
                        action=f"{action}_data",
                        module=getattr(view_func, '__module__', '').split('.')[-2] if '.' in getattr(view_func, '__module__', '') else 'unknown',
                        request=request,
                        description=f"Successfully {action}d data"
                    )
                
                return response
                
            except Exception as e:
                # Log failed modification
                audit_service.log_security_event(
                    user=request.user,
                    action=f"failed_{action}",
                    severity=SecurityEventSeverity.LOW,
                    description=f"Failed to {action} data: {str(e)}",
                    request=request,
                    exception_type=type(e).__name__
                )
                raise
        
        return wrapper
    return decorator


def audit_export_action(export_type='unknown'):
    """
    Decorator for data export actions
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if not request.user.is_authenticated:
                return view_func(request, *args, **kwargs)
            
            try:
                response = view_func(request, *args, **kwargs)
                
                # Log export action
                audit_service.log_user_action(
                    user=request.user,
                    action=f"export_{export_type}",
                    module='exports',
                    request=request,
                    description=f"Successfully exported {export_type} data",
                    export_type=export_type,
                    export_format=request.GET.get('format', 'unknown')
                )
                
                return response
                
            except Exception as e:
                # Log failed export
                audit_service.log_security_event(
                    user=request.user,
                    action=f"failed_export_{export_type}",
                    severity=SecurityEventSeverity.LOW,
                    description=f"Failed to export {export_type} data: {str(e)}",
                    request=request,
                    export_type=export_type,
                    exception_type=type(e).__name__
                )
                raise
        
        return wrapper
    return decorator


def audit_bulk_operation(operation_type='bulk_action'):
    """
    Decorator for bulk operations that need special monitoring
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if not request.user.is_authenticated:
                return view_func(request, *args, **kwargs)
            
            # Get operation details from request
            item_count = 0
            if request.method == 'POST':
                if hasattr(request, 'POST'):
                    # Try to determine number of items from form data
                    item_count = len([k for k in request.POST.keys() if k.startswith('selected_')])
                elif hasattr(request, 'body'):
                    # For JSON requests, this would need to be parsed
                    pass
            
            try:
                response = view_func(request, *args, **kwargs)
                
                # Log bulk operation
                audit_service.log_user_action(
                    user=request.user,
                    action=operation_type,
                    module='bulk_operations',
                    request=request,
                    description=f"Successfully executed {operation_type} on {item_count} items",
                    operation_type=operation_type,
                    item_count=item_count
                )
                
                # Create security alert for large bulk operations
                if item_count > 100:
                    audit_service.log_security_event(
                        user=request.user,
                        action='large_bulk_operation',
                        severity=SecurityEventSeverity.MEDIUM,
                        description=f"Large bulk operation: {operation_type} on {item_count} items",
                        request=request,
                        operation_type=operation_type,
                        item_count=item_count
                    )
                
                return response
                
            except Exception as e:
                # Log failed bulk operation
                audit_service.log_security_event(
                    user=request.user,
                    action=f"failed_{operation_type}",
                    severity=SecurityEventSeverity.MEDIUM,
                    description=f"Failed bulk operation {operation_type}: {str(e)}",
                    request=request,
                    operation_type=operation_type,
                    item_count=item_count,
                    exception_type=type(e).__name__
                )
                raise
        
        return wrapper
    return decorator


class AuditMixin:
    """
    Mixin for class-based views to add audit logging
    """
    audit_action = None
    audit_module = None
    audit_permission = None
    audit_log_data_access = False
    
    def dispatch(self, request, *args, **kwargs):
        """Override dispatch to add audit logging"""
        # Determine action and module
        action = self.audit_action or self.__class__.__name__.lower()
        module = self.audit_module or self.__class__.__module__.split('.')[-2] if '.' in self.__class__.__module__ else 'unknown'
        
        # Check permission if required
        if self.audit_permission and request.user.is_authenticated:
            if not request.user.has_perm(self.audit_permission):
                audit_service.log_permission_check(
                    user=request.user,
                    permission=self.audit_permission,
                    granted=False,
                    request=request,
                    module=module,
                    action=action
                )
                raise PermissionDenied(f"Permission required: {self.audit_permission}")
            else:
                audit_service.log_permission_check(
                    user=request.user,
                    permission=self.audit_permission,
                    granted=True,
                    request=request,
                    module=module,
                    action=action
                )
        
        try:
            response = super().dispatch(request, *args, **kwargs)
            
            # Log successful action
            if request.user.is_authenticated:
                if self.audit_log_data_access and 'pk' in kwargs:
                    audit_service.log_data_access(
                        user=request.user,
                        model_class=getattr(self, 'model', None) or action,
                        object_id=kwargs['pk'],
                        action=action,
                        request=request,
                        module=module
                    )
                else:
                    audit_service.log_user_action(
                        user=request.user,
                        action=action,
                        module=module,
                        request=request,
                        description=f"Successfully executed {action}"
                    )
            
            return response
            
        except Exception as e:
            # Log failed action
            if request.user.is_authenticated:
                audit_service.log_security_event(
                    user=request.user,
                    action=f"failed_{action}",
                    severity=SecurityEventSeverity.LOW,
                    description=f"Failed to execute {action}: {str(e)}",
                    request=request,
                    module=module,
                    exception_type=type(e).__name__
                )
            raise