# -*- coding: utf-8 -*-
"""
Activities Serializers

This module defines Django REST Framework serializers for the activities app.
These serializers handle the conversion between model instances and JSON
representations for API endpoints.

Serializers:
    - ActivityTypeSerializer: Serializer for activity types
    - ActivitySerializer: Serializer for activities
    - AuditLogSerializer: Serializer for audit logs
    - SecurityEventSerializer: Serializer for security events
    - ActivityStatsSerializer: Serializer for activity statistics

Author: AdTlas Development Team
Version: 1.0.0
Last Updated: 2024
"""

from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _

from .models import ActivityType, Activity, AuditLog, SecurityEvent

User = get_user_model()


class ActivityTypeSerializer(serializers.ModelSerializer):
    """
    Serializer for ActivityType model.
    
    This serializer handles the conversion of ActivityType instances
    to and from JSON format for API responses.
    
    Fields:
        - id: Primary key
        - name: Activity type name
        - code: Unique activity type code
        - description: Activity type description
        - is_security_related: Whether the type is security-related
        - retention_days: Data retention period
        - is_active: Whether the type is active
        - activity_count: Number of activities of this type
        - created_at: Creation timestamp
        - updated_at: Last update timestamp
    """
    
    activity_count = serializers.SerializerMethodField()
    
    class Meta:
        model = ActivityType
        fields = [
            'id',
            'name',
            'code',
            'description',
            'is_security_related',
            'retention_days',
            'is_active',
            'activity_count',
            'created_at',
            'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at', 'activity_count']
    
    def get_activity_count(self, obj):
        """
        Get the count of activities for this type.
        
        Args:
            obj (ActivityType): The activity type instance
            
        Returns:
            int: Number of activities
        """
        return obj.activities.count()
    
    def validate_code(self, value):
        """
        Validate that the activity type code is unique.
        
        Args:
            value (str): The code value to validate
            
        Returns:
            str: The validated code
            
        Raises:
            ValidationError: If code is not unique
        """
        if self.instance:
            # Update case - exclude current instance
            if ActivityType.objects.exclude(
                id=self.instance.id
            ).filter(code=value).exists():
                raise serializers.ValidationError(
                    _('Activity type with this code already exists.')
                )
        else:
            # Create case
            if ActivityType.objects.filter(code=value).exists():
                raise serializers.ValidationError(
                    _('Activity type with this code already exists.')
                )
        return value
    
    def validate_retention_days(self, value):
        """
        Validate retention days value.
        
        Args:
            value (int): The retention days value
            
        Returns:
            int: The validated retention days
            
        Raises:
            ValidationError: If value is invalid
        """
        if value < 1:
            raise serializers.ValidationError(
                _('Retention days must be at least 1.')
            )
        if value > 3650:  # 10 years
            raise serializers.ValidationError(
                _('Retention days cannot exceed 3650 (10 years).')
            )
        return value


class UserBasicSerializer(serializers.ModelSerializer):
    """
    Basic serializer for User model (for nested serialization).
    
    This serializer provides minimal user information for
    inclusion in activity serializations.
    """
    
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name', 'is_active']
        read_only_fields = fields


class ContentTypeSerializer(serializers.ModelSerializer):
    """
    Serializer for ContentType model (for nested serialization).
    
    This serializer provides content type information for
    activities that reference other model instances.
    """
    
    class Meta:
        model = ContentType
        fields = ['id', 'app_label', 'model']
        read_only_fields = fields


class ActivitySerializer(serializers.ModelSerializer):
    """
    Serializer for Activity model.
    
    This serializer handles the conversion of Activity instances
    to and from JSON format for API responses.
    
    Fields:
        - id: Primary key
        - user: User who performed the activity
        - activity_type: Type of activity
        - action: Action performed
        - action_display: Human-readable action name
        - description: Activity description
        - ip_address: IP address of the user
        - user_agent: User agent string
        - session_key: Session key
        - extra_data: Additional activity data
        - content_type: Content type of related object
        - object_id: ID of related object
        - related_object_display: String representation of related object
        - success: Whether the activity was successful
        - error_message: Error message if failed
        - created_at: Creation timestamp
        - updated_at: Last update timestamp
    """
    
    user = UserBasicSerializer(read_only=True)
    activity_type = ActivityTypeSerializer(read_only=True)
    content_type = ContentTypeSerializer(read_only=True)
    action_display = serializers.CharField(source='get_action_display', read_only=True)
    related_object_display = serializers.CharField(
        source='get_related_object_display', 
        read_only=True
    )
    
    class Meta:
        model = Activity
        fields = [
            'id',
            'user',
            'activity_type',
            'action',
            'action_display',
            'description',
            'ip_address',
            'user_agent',
            'session_key',
            'extra_data',
            'content_type',
            'object_id',
            'related_object_display',
            'success',
            'error_message',
            'created_at',
            'updated_at'
        ]
        read_only_fields = [
            'id', 'user', 'activity_type', 'action', 'description',
            'ip_address', 'user_agent', 'session_key', 'extra_data',
            'content_type', 'object_id', 'success', 'error_message',
            'created_at', 'updated_at'
        ]
    
    def to_representation(self, instance):
        """
        Convert instance to representation with additional formatting.
        
        Args:
            instance (Activity): The activity instance
            
        Returns:
            dict: Serialized activity data
        """
        data = super().to_representation(instance)
        
        # Format timestamps
        if data['created_at']:
            data['created_at_formatted'] = instance.created_at.strftime(
                '%Y-%m-%d %H:%M:%S'
            )
        
        # Add user display name
        if instance.user:
            data['user_display'] = str(instance.user)
        else:
            data['user_display'] = 'System'
        
        # Add activity type display
        if instance.activity_type:
            data['activity_type_display'] = str(instance.activity_type)
        
        return data


class ActivityCreateSerializer(serializers.Serializer):
    """
    Serializer for creating activities via API.
    
    This serializer handles the creation of new activities
    through API endpoints with validation.
    
    Fields:
        - action: Action being performed
        - description: Activity description
        - activity_type_code: Code of the activity type
        - extra_data: Additional data (optional)
        - success: Whether the activity was successful
        - error_message: Error message if failed
    """
    
    action = serializers.ChoiceField(
        choices=Activity.ACTION_CHOICES,
        help_text=_('The action being performed')
    )
    description = serializers.CharField(
        max_length=1000,
        help_text=_('Description of the activity')
    )
    activity_type_code = serializers.CharField(
        max_length=50,
        default='general',
        help_text=_('Code of the activity type')
    )
    extra_data = serializers.JSONField(
        required=False,
        default=dict,
        help_text=_('Additional data related to the activity')
    )
    success = serializers.BooleanField(
        default=True,
        help_text=_('Whether the activity was successful')
    )
    error_message = serializers.CharField(
        max_length=1000,
        required=False,
        default='',
        help_text=_('Error message if activity failed')
    )
    
    def validate_activity_type_code(self, value):
        """
        Validate that the activity type code exists or can be created.
        
        Args:
            value (str): The activity type code
            
        Returns:
            str: The validated code
        """
        # The code will be validated when creating the activity
        # ActivityType.get_or_create_type will handle creation if needed
        return value
    
    def validate(self, attrs):
        """
        Validate the entire activity data.
        
        Args:
            attrs (dict): The activity attributes
            
        Returns:
            dict: The validated attributes
        """
        # If success is False, error_message should be provided
        if not attrs.get('success', True) and not attrs.get('error_message'):
            raise serializers.ValidationError({
                'error_message': _('Error message is required when success is False.')
            })
        
        return attrs


class AuditLogSerializer(serializers.ModelSerializer):
    """
    Serializer for AuditLog model.
    
    This serializer handles the conversion of AuditLog instances
    to JSON format for API responses.
    
    Fields:
        - id: Primary key
        - user: User who made the change
        - action: Type of change
        - action_display: Human-readable action name
        - model_name: Name of the changed model
        - object_id: ID of the changed object
        - object_repr: String representation of the object
        - changes: Dictionary of field changes
        - before_state: State before change
        - after_state: State after change
        - ip_address: IP address of the user
        - user_agent: User agent string
        - created_at: Creation timestamp
        - updated_at: Last update timestamp
    """
    
    user = UserBasicSerializer(read_only=True)
    action_display = serializers.CharField(source='get_action_display', read_only=True)
    changes_count = serializers.SerializerMethodField()
    
    class Meta:
        model = AuditLog
        fields = [
            'id',
            'user',
            'action',
            'action_display',
            'model_name',
            'object_id',
            'object_repr',
            'changes',
            'changes_count',
            'before_state',
            'after_state',
            'ip_address',
            'user_agent',
            'created_at',
            'updated_at'
        ]
        read_only_fields = fields
    
    def get_changes_count(self, obj):
        """
        Get the count of changed fields.
        
        Args:
            obj (AuditLog): The audit log instance
            
        Returns:
            int: Number of changed fields
        """
        return len(obj.changes) if obj.changes else 0
    
    def to_representation(self, instance):
        """
        Convert instance to representation with additional formatting.
        
        Args:
            instance (AuditLog): The audit log instance
            
        Returns:
            dict: Serialized audit log data
        """
        data = super().to_representation(instance)
        
        # Format timestamps
        if data['created_at']:
            data['created_at_formatted'] = instance.created_at.strftime(
                '%Y-%m-%d %H:%M:%S'
            )
        
        # Add user display name
        if instance.user:
            data['user_display'] = str(instance.user)
        else:
            data['user_display'] = 'System'
        
        # Add summary of changes
        if instance.changes:
            changed_fields = list(instance.changes.keys())
            if len(changed_fields) <= 3:
                data['changes_summary'] = ', '.join(changed_fields)
            else:
                data['changes_summary'] = f"{', '.join(changed_fields[:3])} (+{len(changed_fields)-3} more)"
        else:
            data['changes_summary'] = 'No changes'
        
        return data


class SecurityEventSerializer(serializers.ModelSerializer):
    """
    Serializer for SecurityEvent model.
    
    This serializer handles the conversion of SecurityEvent instances
    to JSON format for API responses.
    
    Fields:
        - id: Primary key
        - event_type: Type of security event
        - event_type_display: Human-readable event type
        - severity: Severity level
        - severity_display: Human-readable severity
        - user: User associated with the event
        - ip_address: IP address where event originated
        - user_agent: User agent string
        - description: Event description
        - details: Additional event details
        - resolved: Whether the event is resolved
        - resolved_by: User who resolved the event
        - resolved_at: Resolution timestamp
        - resolution_notes: Resolution notes
        - created_at: Creation timestamp
        - updated_at: Last update timestamp
    """
    
    user = UserBasicSerializer(read_only=True)
    resolved_by = UserBasicSerializer(read_only=True)
    event_type_display = serializers.CharField(
        source='get_event_type_display', 
        read_only=True
    )
    severity_display = serializers.CharField(
        source='get_severity_display', 
        read_only=True
    )
    
    class Meta:
        model = SecurityEvent
        fields = [
            'id',
            'event_type',
            'event_type_display',
            'severity',
            'severity_display',
            'user',
            'ip_address',
            'user_agent',
            'description',
            'details',
            'resolved',
            'resolved_by',
            'resolved_at',
            'resolution_notes',
            'created_at',
            'updated_at'
        ]
        read_only_fields = [
            'id', 'event_type', 'severity', 'user', 'ip_address',
            'user_agent', 'description', 'details', 'created_at',
            'updated_at'
        ]
    
    def to_representation(self, instance):
        """
        Convert instance to representation with additional formatting.
        
        Args:
            instance (SecurityEvent): The security event instance
            
        Returns:
            dict: Serialized security event data
        """
        data = super().to_representation(instance)
        
        # Format timestamps
        if data['created_at']:
            data['created_at_formatted'] = instance.created_at.strftime(
                '%Y-%m-%d %H:%M:%S'
            )
        
        if data['resolved_at']:
            data['resolved_at_formatted'] = instance.resolved_at.strftime(
                '%Y-%m-%d %H:%M:%S'
            )
        
        # Add user display name
        if instance.user:
            data['user_display'] = str(instance.user)
        else:
            data['user_display'] = 'Unknown'
        
        # Add resolved by display name
        if instance.resolved_by:
            data['resolved_by_display'] = str(instance.resolved_by)
        
        # Add severity badge color
        severity_colors = {
            'low': 'success',
            'medium': 'warning',
            'high': 'danger',
            'critical': 'danger'
        }
        data['severity_color'] = severity_colors.get(instance.severity, 'secondary')
        
        return data


class SecurityEventUpdateSerializer(serializers.ModelSerializer):
    """
    Serializer for updating security events.
    
    This serializer handles updates to security events,
    particularly for resolution.
    
    Fields:
        - resolved: Whether the event is resolved
        - resolution_notes: Notes about the resolution
    """
    
    class Meta:
        model = SecurityEvent
        fields = ['resolved', 'resolution_notes']
    
    def update(self, instance, validated_data):
        """
        Update the security event with resolution information.
        
        Args:
            instance (SecurityEvent): The security event instance
            validated_data (dict): The validated update data
            
        Returns:
            SecurityEvent: The updated instance
        """
        if validated_data.get('resolved') and not instance.resolved:
            # Mark as resolved
            instance.resolve(
                resolved_by=self.context['request'].user,
                resolution_notes=validated_data.get('resolution_notes', '')
            )
        else:
            # Regular update
            for attr, value in validated_data.items():
                setattr(instance, attr, value)
            instance.save()
        
        return instance


class ActivityStatsSerializer(serializers.Serializer):
    """
    Serializer for activity statistics.
    
    This serializer handles the serialization of activity
    statistics for dashboard and reporting purposes.
    
    Fields:
        - total_activities: Total number of activities
        - today_activities: Activities from today
        - week_activities: Activities from this week
        - month_activities: Activities from this month
        - successful_activities: Number of successful activities
        - failed_activities: Number of failed activities
        - action_breakdown: Breakdown by action type
        - trend_data: Activity trend over time
    """
    
    total_activities = serializers.IntegerField()
    today_activities = serializers.IntegerField()
    week_activities = serializers.IntegerField()
    month_activities = serializers.IntegerField()
    successful_activities = serializers.IntegerField()
    failed_activities = serializers.IntegerField()
    action_breakdown = serializers.ListField(
        child=serializers.DictField()
    )
    trend_data = serializers.ListField(
        child=serializers.DictField()
    )


class ActivityExportSerializer(serializers.Serializer):
    """
    Serializer for activity export requests.
    
    This serializer handles the validation of activity
    export parameters.
    
    Fields:
        - format: Export format (json, csv)
        - date_from: Start date for export
        - date_to: End date for export
        - include_extra_data: Whether to include extra data
    """
    
    FORMAT_CHOICES = [
        ('json', 'JSON'),
        ('csv', 'CSV'),
    ]
    
    format = serializers.ChoiceField(
        choices=FORMAT_CHOICES,
        default='json',
        help_text=_('Export format')
    )
    date_from = serializers.DateField(
        required=False,
        help_text=_('Start date for export (YYYY-MM-DD)')
    )
    date_to = serializers.DateField(
        required=False,
        help_text=_('End date for export (YYYY-MM-DD)')
    )
    include_extra_data = serializers.BooleanField(
        default=False,
        help_text=_('Whether to include extra data in export')
    )
    
    def validate(self, attrs):
        """
        Validate the export parameters.
        
        Args:
            attrs (dict): The export attributes
            
        Returns:
            dict: The validated attributes
        """
        date_from = attrs.get('date_from')
        date_to = attrs.get('date_to')
        
        if date_from and date_to and date_from > date_to:
            raise serializers.ValidationError({
                'date_from': _('Start date must be before end date.')
            })
        
        return attrs