"""Core Serializers

This module contains base serializers and common serialization utilities
for the Adtlas project's REST API.
"""

import logging
from typing import Any, Dict, List, Optional
from datetime import datetime

from django.contrib.auth import get_user_model
from django.utils import timezone
from rest_framework import serializers
from rest_framework.fields import empty
from rest_framework.utils import model_meta

from .models import Setting, ActivityLog
from .utils import format_datetime, get_file_size_display


User = get_user_model()
logger = logging.getLogger(__name__)


# ============================================================================
# Base Serializers
# ============================================================================

class BaseModelSerializer(serializers.ModelSerializer):
    """Base serializer with common functionality."""
    
    # Read-only fields that are commonly used
    id = serializers.ReadOnlyField()
    created_at = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
    updated_at = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
    
    class Meta:
        abstract = True
    
    def __init__(self, *args, **kwargs):
        """Initialize serializer with request context."""
        super().__init__(*args, **kwargs)
        
        # Add current user to context if available
        request = self.context.get('request')
        if request and hasattr(request, 'user'):
            self.context['current_user'] = request.user
    
    def to_representation(self, instance):
        """Convert model instance to representation."""
        data = super().to_representation(instance)
        
        # Add computed fields
        if hasattr(instance, 'created_at') and instance.created_at:
            data['created_at_display'] = format_datetime(instance.created_at)
        
        if hasattr(instance, 'updated_at') and instance.updated_at:
            data['updated_at_display'] = format_datetime(instance.updated_at)
        
        return data
    
    def create(self, validated_data):
        """Create model instance with audit fields."""
        # Set created_by if model supports it
        current_user = self.context.get('current_user')
        if current_user and current_user.is_authenticated:
            if hasattr(self.Meta.model, 'created_by'):
                validated_data['created_by'] = current_user
        
        return super().create(validated_data)
    
    def update(self, instance, validated_data):
        """Update model instance with audit fields."""
        # Set updated_by if model supports it
        current_user = self.context.get('current_user')
        if current_user and current_user.is_authenticated:
            if hasattr(instance, 'updated_by'):
                validated_data['updated_by'] = current_user
        
        return super().update(instance, validated_data)


class TimestampedSerializer(serializers.ModelSerializer):
    """Serializer for models with timestamp fields."""
    
    created_at = serializers.DateTimeField(read_only=True)
    updated_at = serializers.DateTimeField(read_only=True)
    
    class Meta:
        abstract = True


class AuditSerializer(BaseModelSerializer):
    """Serializer for models with audit fields."""
    
    created_by = serializers.StringRelatedField(read_only=True)
    updated_by = serializers.StringRelatedField(read_only=True)
    
    class Meta:
        abstract = True


class SoftDeleteSerializer(BaseModelSerializer):
    """Serializer for models with soft delete."""
    
    is_deleted = serializers.BooleanField(read_only=True)
    deleted_at = serializers.DateTimeField(read_only=True)
    
    class Meta:
        abstract = True


# ============================================================================
# User Serializers
# ============================================================================

class UserBasicSerializer(serializers.ModelSerializer):
    """Basic user serializer for references."""
    
    full_name = serializers.SerializerMethodField()
    avatar_url = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'first_name', 'last_name', 'full_name', 'avatar_url']
        read_only_fields = ['id', 'username', 'email']
    
    def get_full_name(self, obj):
        """Get user's full name."""
        return obj.get_full_name() if hasattr(obj, 'get_full_name') else f"{obj.first_name} {obj.last_name}".strip()
    
    def get_avatar_url(self, obj):
        """Get user's avatar URL."""
        if hasattr(obj, 'avatar') and obj.avatar:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.avatar.url)
            return obj.avatar.url
        return None


class UserDetailSerializer(BaseModelSerializer):
    """Detailed user serializer."""
    
    full_name = serializers.SerializerMethodField()
    avatar_url = serializers.SerializerMethodField()
    roles = serializers.SerializerMethodField()
    permissions = serializers.SerializerMethodField()
    last_login_display = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = [
            'id', 'username', 'email', 'first_name', 'last_name', 'full_name',
            'avatar_url', 'is_active', 'is_staff', 'is_superuser', 'date_joined',
            'last_login', 'last_login_display', 'roles', 'permissions'
        ]
        read_only_fields = [
            'id', 'username', 'date_joined', 'last_login', 'is_staff', 'is_superuser'
        ]
    
    def get_full_name(self, obj):
        """Get user's full name."""
        return obj.get_full_name() if hasattr(obj, 'get_full_name') else f"{obj.first_name} {obj.last_name}".strip()
    
    def get_avatar_url(self, obj):
        """Get user's avatar URL."""
        if hasattr(obj, 'avatar') and obj.avatar:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.avatar.url)
            return obj.avatar.url
        return None
    
    def get_roles(self, obj):
        """Get user's roles."""
        roles = []
        if hasattr(obj, 'roles'):
            roles = [role.name for role in obj.roles.all()]
        elif hasattr(obj, 'userroleassignment_set'):
            roles = [
                assignment.role.name 
                for assignment in obj.userroleassignment_set.filter(is_active=True)
            ]
        return roles
    
    def get_permissions(self, obj):
        """Get user's permissions."""
        return list(obj.get_all_permissions())
    
    def get_last_login_display(self, obj):
        """Get formatted last login time."""
        if obj.last_login:
            return format_datetime(obj.last_login)
        return None


# ============================================================================
# Core Model Serializers
# ============================================================================

class SettingSerializer(BaseModelSerializer):
    """Serializer for application settings."""
    
    value_display = serializers.SerializerMethodField()
    
    class Meta:
        model = Setting
        fields = [
            'id', 'key', 'value', 'value_display', 'value_type', 'description',
            'is_public', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_value_display(self, obj):
        """Get formatted value for display."""
        return obj.get_value_display()
    
    def validate_key(self, value):
        """Validate setting key."""
        if not value or not value.strip():
            raise serializers.ValidationError("Setting key cannot be empty.")
        
        # Check for duplicate keys (excluding current instance)
        queryset = Setting.objects.filter(key=value)
        if self.instance:
            queryset = queryset.exclude(pk=self.instance.pk)
        
        if queryset.exists():
            raise serializers.ValidationError("Setting with this key already exists.")
        
        return value


class ActivityLogSerializer(BaseModelSerializer):
    """Serializer for activity logs."""
    
    user = UserBasicSerializer(read_only=True)
    activity_type_display = serializers.SerializerMethodField()
    created_at_display = serializers.SerializerMethodField()
    
    class Meta:
        model = ActivityLog
        fields = [
            'id', 'user', 'activity_type', 'activity_type_display', 'description',
            'object_type', 'object_id', 'ip_address', 'user_agent', 'extra_data',
            'created_at', 'created_at_display'
        ]
        read_only_fields = ['id', 'created_at']
    
    def get_activity_type_display(self, obj):
        """Get display name for activity type."""
        return obj.get_activity_type_display()
    
    def get_created_at_display(self, obj):
        """Get formatted creation time."""
        return format_datetime(obj.created_at)


# ============================================================================
# File Upload Serializers
# ============================================================================

class FileUploadSerializer(serializers.Serializer):
    """Serializer for file uploads."""
    
    file = serializers.FileField()
    description = serializers.CharField(max_length=500, required=False, allow_blank=True)
    
    def validate_file(self, value):
        """Validate uploaded file."""
        # Check file size (10MB limit)
        max_size = 10 * 1024 * 1024  # 10MB
        if value.size > max_size:
            raise serializers.ValidationError(
                f"File size {get_file_size_display(value.size)} exceeds maximum allowed size of {get_file_size_display(max_size)}."
            )
        
        return value
    
    def to_representation(self, instance):
        """Convert to representation."""
        data = super().to_representation(instance)
        
        if 'file' in data and hasattr(instance.get('file'), 'url'):
            request = self.context.get('request')
            if request:
                data['file_url'] = request.build_absolute_uri(instance['file'].url)
            else:
                data['file_url'] = instance['file'].url
            
            data['file_size'] = instance['file'].size
            data['file_size_display'] = get_file_size_display(instance['file'].size)
        
        return data


class ImageUploadSerializer(FileUploadSerializer):
    """Serializer for image uploads."""
    
    def validate_file(self, value):
        """Validate uploaded image."""
        value = super().validate_file(value)
        
        # Check if file is an image
        allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
        if hasattr(value, 'content_type') and value.content_type not in allowed_types:
            raise serializers.ValidationError(
                f"File type {value.content_type} is not allowed. Allowed types: {', '.join(allowed_types)}"
            )
        
        return value


# ============================================================================
# Generic Serializers
# ============================================================================

class BulkActionSerializer(serializers.Serializer):
    """Serializer for bulk actions."""
    
    ids = serializers.ListField(
        child=serializers.IntegerField(),
        min_length=1,
        help_text="List of object IDs to perform action on"
    )
    action = serializers.CharField(
        max_length=50,
        help_text="Action to perform"
    )
    
    def validate_ids(self, value):
        """Validate IDs list."""
        if not value:
            raise serializers.ValidationError("At least one ID must be provided.")
        
        # Remove duplicates while preserving order
        seen = set()
        unique_ids = []
        for id_val in value:
            if id_val not in seen:
                seen.add(id_val)
                unique_ids.append(id_val)
        
        return unique_ids


class SearchSerializer(serializers.Serializer):
    """Serializer for search requests."""
    
    query = serializers.CharField(
        max_length=200,
        required=True,
        help_text="Search query"
    )
    filters = serializers.DictField(
        required=False,
        help_text="Additional filters"
    )
    sort_by = serializers.CharField(
        max_length=50,
        required=False,
        help_text="Field to sort by"
    )
    sort_order = serializers.ChoiceField(
        choices=[('asc', 'Ascending'), ('desc', 'Descending')],
        default='desc',
        required=False
    )
    
    def validate_query(self, value):
        """Validate search query."""
        if not value or not value.strip():
            raise serializers.ValidationError("Search query cannot be empty.")
        
        # Minimum length check
        if len(value.strip()) < 2:
            raise serializers.ValidationError("Search query must be at least 2 characters long.")
        
        return value.strip()


class ExportSerializer(serializers.Serializer):
    """Serializer for data export requests."""
    
    format = serializers.ChoiceField(
        choices=[('csv', 'CSV'), ('xlsx', 'Excel'), ('json', 'JSON'), ('pdf', 'PDF')],
        default='csv'
    )
    fields = serializers.ListField(
        child=serializers.CharField(),
        required=False,
        help_text="Fields to include in export"
    )
    filters = serializers.DictField(
        required=False,
        help_text="Filters to apply"
    )
    include_headers = serializers.BooleanField(
        default=True,
        help_text="Include headers in export"
    )


# ============================================================================
# Response Serializers
# ============================================================================

class SuccessResponseSerializer(serializers.Serializer):
    """Serializer for success responses."""
    
    success = serializers.BooleanField(default=True)
    message = serializers.CharField(max_length=200)
    data = serializers.DictField(required=False)


class ErrorResponseSerializer(serializers.Serializer):
    """Serializer for error responses."""
    
    success = serializers.BooleanField(default=False)
    error = serializers.CharField(max_length=200)
    details = serializers.DictField(required=False)
    code = serializers.CharField(max_length=50, required=False)


class PaginationResponseSerializer(serializers.Serializer):
    """Serializer for paginated responses."""
    
    count = serializers.IntegerField()
    next = serializers.URLField(allow_null=True)
    previous = serializers.URLField(allow_null=True)
    results = serializers.ListField()


# ============================================================================
# Validation Serializers
# ============================================================================

class PasswordValidationSerializer(serializers.Serializer):
    """Serializer for password validation."""
    
    password = serializers.CharField(write_only=True)
    
    def validate_password(self, value):
        """Validate password strength."""
        from .validators import validate_password_strength
        
        result = validate_password_strength(value)
        
        if result['score'] < 3:  # Minimum acceptable score
            raise serializers.ValidationError({
                'message': f"Password strength: {result['strength']}",
                'feedback': result['feedback']
            })
        
        return value


class EmailValidationSerializer(serializers.Serializer):
    """Serializer for email validation."""
    
    email = serializers.EmailField()
    
    def validate_email(self, value):
        """Validate email address."""
        # Check if email is already in use
        if User.objects.filter(email=value).exists():
            raise serializers.ValidationError("This email address is already in use.")
        
        return value


# ============================================================================
# Utility Functions
# ============================================================================

def get_serializer_fields(serializer_class):
    """Get list of fields from serializer class.
    
    Args:
        serializer_class: Serializer class
        
    Returns:
        List of field names
    """
    serializer = serializer_class()
    return list(serializer.fields.keys())


def serialize_model_instance(instance, serializer_class, context=None):
    """Serialize a model instance.
    
    Args:
        instance: Model instance to serialize
        serializer_class: Serializer class to use
        context: Serializer context
        
    Returns:
        Serialized data
    """
    context = context or {}
    serializer = serializer_class(instance, context=context)
    return serializer.data


def serialize_queryset(queryset, serializer_class, context=None):
    """Serialize a queryset.
    
    Args:
        queryset: QuerySet to serialize
        serializer_class: Serializer class to use
        context: Serializer context
        
    Returns:
        List of serialized data
    """
    context = context or {}
    serializer = serializer_class(queryset, many=True, context=context)
    return serializer.data


def validate_serializer_data(serializer_class, data, context=None):
    """Validate data using serializer.
    
    Args:
        serializer_class: Serializer class to use
        data: Data to validate
        context: Serializer context
        
    Returns:
        Tuple of (is_valid, validated_data, errors)
    """
    context = context or {}
    serializer = serializer_class(data=data, context=context)
    
    is_valid = serializer.is_valid()
    validated_data = serializer.validated_data if is_valid else None
    errors = serializer.errors if not is_valid else None
    
    return is_valid, validated_data, errors