"""
Audit Logging Utilities
Provides functions to log user actions throughout the application
"""

import json
from django.utils import timezone
from django.contrib.auth import get_user_model
from stiftung.models import AuditLog

User = get_user_model()


def get_client_ip(request):
    """Extract the client IP address from the request"""
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip


def log_action(request, action, entity_type, entity_id, entity_name, description, changes=None):
    """
    Log a user action to the audit log
    
    Args:
        request: Django request object
        action: Action type (create, update, delete, etc.)
        entity_type: Type of entity (destinataer, land, etc.)
        entity_id: ID of the entity
        entity_name: Human-readable name of the entity
        description: Description of the action
        changes: Dictionary of field changes (optional)
    """
    user = request.user if request.user.is_authenticated else None
    username = user.username if user else 'Anonymous'
    
    # Get request metadata
    ip_address = get_client_ip(request)
    user_agent = request.META.get('HTTP_USER_AGENT', '')
    session_key = request.session.session_key if hasattr(request, 'session') else ''
    
    # Create audit log entry
    audit_entry = AuditLog.objects.create(
        user=user,
        username=username,
        action=action,
        entity_type=entity_type,
        entity_id=str(entity_id) if entity_id else '',
        entity_name=entity_name,
        description=description,
        changes=changes,
        ip_address=ip_address,
        user_agent=user_agent[:500],  # Truncate to avoid very long user agents
        session_key=session_key
    )
    
    return audit_entry


def log_create(request, entity_type, entity_id, entity_name, description=None):
    """Log entity creation"""
    if not description:
        description = f"Neue {entity_type.replace('_', ' ').title()} '{entity_name}' wurde erstellt"
    
    return log_action(
        request=request,
        action='create',
        entity_type=entity_type,
        entity_id=entity_id,
        entity_name=entity_name,
        description=description
    )


def log_update(request, entity_type, entity_id, entity_name, changes, description=None):
    """Log entity update with field changes"""
    if not description:
        changed_fields = list(changes.keys()) if changes else []
        fields_str = ", ".join(changed_fields)
        description = f"{entity_type.replace('_', ' ').title()} '{entity_name}' wurde aktualisiert: {fields_str}"
    
    return log_action(
        request=request,
        action='update',
        entity_type=entity_type,
        entity_id=entity_id,
        entity_name=entity_name,
        description=description,
        changes=changes
    )


def log_delete(request, entity_type, entity_id, entity_name, description=None):
    """Log entity deletion"""
    if not description:
        description = f"{entity_type.replace('_', ' ').title()} '{entity_name}' wurde gelöscht"
    
    return log_action(
        request=request,
        action='delete',
        entity_type=entity_type,
        entity_id=entity_id,
        entity_name=entity_name,
        description=description
    )


def log_link(request, entity_type, entity_id, entity_name, target_type, target_name, description=None):
    """Log entity linking"""
    if not description:
        description = f"{entity_type.replace('_', ' ').title()} '{entity_name}' wurde mit {target_type.replace('_', ' ')} '{target_name}' verknüpft"
    
    return log_action(
        request=request,
        action='link',
        entity_type=entity_type,
        entity_id=entity_id,
        entity_name=entity_name,
        description=description
    )


def log_unlink(request, entity_type, entity_id, entity_name, target_type, target_name, description=None):
    """Log entity unlinking"""
    if not description:
        description = f"Verknüpfung zwischen {entity_type.replace('_', ' ').title()} '{entity_name}' und {target_type.replace('_', ' ')} '{target_name}' wurde entfernt"
    
    return log_action(
        request=request,
        action='unlink',
        entity_type=entity_type,
        entity_id=entity_id,
        entity_name=entity_name,
        description=description
    )


def log_system_action(request, action, description, details=None):
    """Log system-level actions like backup, restore, etc."""
    return log_action(
        request=request,
        action=action,
        entity_type='system',
        entity_id='',
        entity_name='System',
        description=description,
        changes=details
    )


def track_model_changes(old_instance, new_instance, exclude_fields=None):
    """
    Track changes between model instances
    
    Args:
        old_instance: Original model instance
        new_instance: Updated model instance  
        exclude_fields: List of fields to exclude from tracking
        
    Returns:
        Dictionary of changes in format {field: {'old': old_value, 'new': new_value}}
    """
    if exclude_fields is None:
        exclude_fields = ['id', 'erstellt_am', 'aktualisiert_am', 'created_at', 'updated_at']
    
    changes = {}
    
    if old_instance and new_instance:
        for field in new_instance._meta.fields:
            field_name = field.name
            
            if field_name in exclude_fields:
                continue
                
            old_value = getattr(old_instance, field_name, None)
            new_value = getattr(new_instance, field_name, None)
            
            # Convert to string for comparison
            old_str = str(old_value) if old_value is not None else None
            new_str = str(new_value) if new_value is not None else None
            
            if old_str != new_str:
                changes[field_name] = {
                    'old': old_str,
                    'new': new_str
                }
    
    return changes


class AuditLogMixin:
    """
    Mixin for views that provides audit logging functionality
    """
    audit_entity_type = None
    audit_entity_name_field = 'name'
    
    def get_audit_entity_type(self):
        """Get the entity type for audit logging"""
        if self.audit_entity_type:
            return self.audit_entity_type
        
        # Try to derive from model name
        if hasattr(self, 'model') and self.model:
            return self.model.__name__.lower()
        
        return 'unknown'
    
    def get_audit_entity_name(self, instance):
        """Get the entity name for audit logging"""
        if hasattr(instance, self.audit_entity_name_field):
            return str(getattr(instance, self.audit_entity_name_field))
        elif hasattr(instance, '__str__'):
            return str(instance)
        else:
            return f"{self.get_audit_entity_type()} #{instance.pk}"
    
    def log_create_action(self, instance):
        """Log creation of an instance"""
        log_create(
            request=self.request,
            entity_type=self.get_audit_entity_type(),
            entity_id=instance.pk,
            entity_name=self.get_audit_entity_name(instance)
        )
    
    def log_update_action(self, old_instance, new_instance):
        """Log update of an instance"""
        changes = track_model_changes(old_instance, new_instance)
        if changes:  # Only log if there are actual changes
            log_update(
                request=self.request,
                entity_type=self.get_audit_entity_type(),
                entity_id=new_instance.pk,
                entity_name=self.get_audit_entity_name(new_instance),
                changes=changes
            )
    
    def log_delete_action(self, instance):
        """Log deletion of an instance"""
        log_delete(
            request=self.request,
            entity_type=self.get_audit_entity_type(),
            entity_id=instance.pk,
            entity_name=self.get_audit_entity_name(instance)
        )


# Simple login/logout audit helpers expected by views
def log_login(request, user):
    """Log a successful user login."""
    try:
        return log_action(
            request=request,
            action='login',
            entity_type='user',
            entity_id=user.pk,
            entity_name=user.get_username(),
            description=f"User '{user.get_username()}' logged in"
        )
    except Exception:
        return None


def log_logout(request, user):
    """Log a successful user logout."""
    try:
        username = user.get_username() if user else 'Unknown'
        return log_action(
            request=request,
            action='logout',
            entity_type='user',
            entity_id=getattr(user, 'pk', ''),
            entity_name=username,
            description=f"User '{username}' logged out"
        )
    except Exception:
        return None
