"""Creative Management Serializers

Django REST Framework serializers for creative asset management.
Provides comprehensive serialization for all creative-related models.

Features:
- Basic CRUD serializers
- Nested relationship serializers
- File upload serializers
- Bulk operation serializers
- Performance data serializers
- Validation and processing

Serializers:
- CreativeSerializer: Basic creative operations
- CreativeDetailSerializer: Detailed creative with relationships
- CreativeCreateSerializer: Creative creation with validation
- CreativeVersionSerializer: Version management
- CreativeTemplateSerializer: Template operations
- CreativeApprovalSerializer: Approval workflow
- CreativePerformanceSerializer: Performance metrics
- CreativeUploadSerializer: File upload handling
- BulkCreativeSerializer: Bulk operations

Validation:
- File type and size validation
- Creative naming conventions
- Template variable validation
- Performance data validation
- Compliance checking
"""

import os
import mimetypes
from decimal import Decimal
from datetime import datetime, timedelta

from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.validators import FileExtensionValidator
from django.utils import timezone
from django.conf import settings

from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from .models import (
    Creative, CreativeVersion, CreativeFormat, CreativeTemplate,
    CreativeAsset, CreativeApproval, CreativePerformance,
    CreativeTag, CreativeCompliance, CreativeVariant
)
from apps.campaigns.models import Campaign
from apps.authentication.serializers import UserSerializer


class CreativeTagSerializer(serializers.ModelSerializer):
    """Creative tag serializer."""
    
    class Meta:
        model = CreativeTag
        fields = ['id', 'name', 'color', 'description']
        read_only_fields = ['id']


class CreativeAssetSerializer(serializers.ModelSerializer):
    """Creative asset serializer."""
    
    file_url = serializers.SerializerMethodField()
    file_size_display = serializers.SerializerMethodField()
    
    class Meta:
        model = CreativeAsset
        fields = [
            'id', 'asset_type', 'name', 'file', 'file_url',
            'file_size', 'file_size_display', 'metadata',
            'order', 'created_at'
        ]
        read_only_fields = ['id', 'file_size', 'created_at']
    
    def get_file_url(self, obj):
        """Get file URL."""
        if obj.file:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.file.url)
            return obj.file.url
        return None
    
    def get_file_size_display(self, obj):
        """Get human-readable file size."""
        if obj.file_size:
            return obj.get_file_size_display()
        return None


class CreativeVersionSerializer(serializers.ModelSerializer):
    """Creative version serializer."""
    
    created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True)
    file_url = serializers.SerializerMethodField()
    
    class Meta:
        model = CreativeVersion
        fields = [
            'id', 'version_number', 'file', 'file_url',
            'file_size', 'changes', 'created_by',
            'created_by_name', 'created_at'
        ]
        read_only_fields = ['id', 'version_number', 'file_size', 'created_at']
    
    def get_file_url(self, obj):
        """Get file URL."""
        if obj.file:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.file.url)
            return obj.file.url
        return None


class CreativeApprovalSerializer(serializers.ModelSerializer):
    """Creative approval serializer."""
    
    reviewer_name = serializers.CharField(source='reviewer.get_full_name', read_only=True)
    creative_name = serializers.CharField(source='creative.name', read_only=True)
    approval_status_display = serializers.CharField(
        source='get_approval_status_display', read_only=True
    )
    
    class Meta:
        model = CreativeApproval
        fields = [
            'id', 'creative', 'creative_name', 'reviewer',
            'reviewer_name', 'approval_status', 'approval_status_display',
            'comments', 'reviewed_at', 'created_at'
        ]
        read_only_fields = ['id', 'reviewed_at', 'created_at']


class CreativePerformanceSerializer(serializers.ModelSerializer):
    """Creative performance serializer."""
    
    ctr = serializers.SerializerMethodField()
    conversion_rate = serializers.SerializerMethodField()
    roas = serializers.SerializerMethodField()
    
    class Meta:
        model = CreativePerformance
        fields = [
            'id', 'creative', 'date', 'impressions', 'clicks',
            'conversions', 'spend', 'revenue', 'ctr',
            'conversion_rate', 'roas', 'created_at'
        ]
        read_only_fields = ['id', 'created_at']
    
    def get_ctr(self, obj):
        """Calculate click-through rate."""
        if obj.impressions and obj.impressions > 0:
            return round((obj.clicks / obj.impressions) * 100, 2)
        return 0
    
    def get_conversion_rate(self, obj):
        """Calculate conversion rate."""
        if obj.clicks and obj.clicks > 0:
            return round((obj.conversions / obj.clicks) * 100, 2)
        return 0
    
    def get_roas(self, obj):
        """Calculate return on ad spend."""
        if obj.spend and obj.spend > 0:
            return round(float(obj.revenue / obj.spend), 2)
        return 0


class CreativeComplianceSerializer(serializers.ModelSerializer):
    """Creative compliance serializer."""
    
    compliance_status_display = serializers.CharField(
        source='get_compliance_status_display', read_only=True
    )
    
    class Meta:
        model = CreativeCompliance
        fields = [
            'id', 'creative', 'compliance_status', 'compliance_status_display',
            'compliance_score', 'issues', 'recommendations',
            'checked_at', 'created_at'
        ]
        read_only_fields = ['id', 'checked_at', 'created_at']


class CreativeVariantSerializer(serializers.ModelSerializer):
    """Creative variant serializer."""
    
    performance = CreativePerformanceSerializer(many=True, read_only=True)
    
    class Meta:
        model = CreativeVariant
        fields = [
            'id', 'creative', 'variant_name', 'variant_data',
            'is_control', 'traffic_allocation', 'performance',
            'created_at'
        ]
        read_only_fields = ['id', 'created_at']


class CreativeSerializer(serializers.ModelSerializer):
    """Basic creative serializer."""
    
    campaign_name = serializers.CharField(source='campaign.name', read_only=True)
    created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True)
    creative_type_display = serializers.CharField(
        source='get_creative_type_display', read_only=True
    )
    creative_status_display = serializers.CharField(
        source='get_creative_status_display', read_only=True
    )
    file_url = serializers.SerializerMethodField()
    thumbnail_url = serializers.SerializerMethodField()
    file_size_display = serializers.SerializerMethodField()
    tags = CreativeTagSerializer(many=True, read_only=True)
    
    class Meta:
        model = Creative
        fields = [
            'id', 'name', 'description', 'creative_type',
            'creative_type_display', 'creative_status',
            'creative_status_display', 'campaign', 'campaign_name',
            'primary_file', 'file_url', 'thumbnail', 'thumbnail_url',
            'file_size', 'file_size_display', 'duration', 'dimensions',
            'priority', 'deadline', 'is_compliant', 'compliance_score',
            'impressions', 'clicks', 'conversions', 'tags',
            'created_by', 'created_by_name', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'file_size', 'duration', 'dimensions',
            'is_compliant', 'compliance_score', 'impressions',
            'clicks', 'conversions', 'created_at', 'updated_at'
        ]
    
    def get_file_url(self, obj):
        """Get primary file URL."""
        if obj.primary_file:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.primary_file.url)
            return obj.primary_file.url
        return None
    
    def get_thumbnail_url(self, obj):
        """Get thumbnail URL."""
        if obj.thumbnail:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.thumbnail.url)
            return obj.thumbnail.url
        return None
    
    def get_file_size_display(self, obj):
        """Get human-readable file size."""
        if obj.file_size:
            return obj.get_file_size_display()
        return None


class CreativeDetailSerializer(CreativeSerializer):
    """Detailed creative serializer with relationships."""
    
    versions = CreativeVersionSerializer(many=True, read_only=True)
    assets = CreativeAssetSerializer(many=True, read_only=True)
    approvals = CreativeApprovalSerializer(many=True, read_only=True)
    compliance = CreativeComplianceSerializer(read_only=True)
    variants = CreativeVariantSerializer(many=True, read_only=True)
    performance_data = CreativePerformanceSerializer(many=True, read_only=True)
    created_by = UserSerializer(read_only=True)
    updated_by = UserSerializer(read_only=True)
    
    class Meta(CreativeSerializer.Meta):
        fields = CreativeSerializer.Meta.fields + [
            'versions', 'assets', 'approvals', 'compliance',
            'variants', 'performance_data', 'updated_by'
        ]


class CreativeCreateSerializer(serializers.ModelSerializer):
    """Creative creation serializer with validation."""
    
    tags = serializers.PrimaryKeyRelatedField(
        queryset=CreativeTag.objects.all(),
        many=True,
        required=False
    )
    
    class Meta:
        model = Creative
        fields = [
            'name', 'description', 'creative_type', 'campaign',
            'primary_file', 'priority', 'deadline', 'tags'
        ]
    
    def validate_name(self, value):
        """Validate creative name."""
        if len(value) < 3:
            raise serializers.ValidationError(
                'Creative name must be at least 3 characters long.'
            )
        
        # Check for duplicate names in the same campaign
        campaign = self.initial_data.get('campaign')
        if campaign:
            existing = Creative.objects.filter(
                name=value,
                campaign_id=campaign
            ).exclude(pk=self.instance.pk if self.instance else None)
            
            if existing.exists():
                raise serializers.ValidationError(
                    'A creative with this name already exists in the campaign.'
                )
        
        return value
    
    def validate_primary_file(self, value):
        """Validate uploaded file."""
        if not value:
            return value
        
        # Check file size (50MB limit)
        max_size = 50 * 1024 * 1024  # 50MB
        if value.size > max_size:
            raise serializers.ValidationError(
                f'File size cannot exceed {max_size // (1024 * 1024)}MB.'
            )
        
        # Check file type
        allowed_types = {
            'image': ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
            'video': ['video/mp4', 'video/avi', 'video/mov', 'video/wmv'],
            'audio': ['audio/mp3', 'audio/wav', 'audio/aac'],
            'document': ['application/pdf', 'text/html']
        }
        
        content_type = getattr(value, 'content_type', None)
        if content_type:
            valid_types = []
            for types in allowed_types.values():
                valid_types.extend(types)
            
            if content_type not in valid_types:
                raise serializers.ValidationError(
                    f'File type {content_type} is not supported.'
                )
        
        return value
    
    def validate_deadline(self, value):
        """Validate deadline."""
        if value and value <= timezone.now().date():
            raise serializers.ValidationError(
                'Deadline must be in the future.'
            )
        return value
    
    def validate(self, attrs):
        """Validate creative data."""
        # Validate campaign is active
        campaign = attrs.get('campaign')
        if campaign and campaign.status != 'active':
            raise serializers.ValidationError(
                'Cannot create creative for inactive campaign.'
            )
        
        return attrs


class CreativeTemplateSerializer(serializers.ModelSerializer):
    """Creative template serializer."""
    
    template_type_display = serializers.CharField(
        source='get_template_type_display', read_only=True
    )
    created_by_name = serializers.CharField(
        source='created_by.get_full_name', read_only=True
    )
    preview_url = serializers.SerializerMethodField()
    
    class Meta:
        model = CreativeTemplate
        fields = [
            'id', 'name', 'description', 'template_type',
            'template_type_display', 'template_data', 'variables',
            'preview_image', 'preview_url', 'usage_count',
            'is_active', 'created_by', 'created_by_name',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'usage_count', 'created_at', 'updated_at']
    
    def get_preview_url(self, obj):
        """Get preview image URL."""
        if obj.preview_image:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.preview_image.url)
            return obj.preview_image.url
        return None
    
    def validate_template_data(self, value):
        """Validate template data structure."""
        if not isinstance(value, dict):
            raise serializers.ValidationError(
                'Template data must be a valid JSON object.'
            )
        
        # Check required fields
        required_fields = ['content', 'styles']
        for field in required_fields:
            if field not in value:
                raise serializers.ValidationError(
                    f'Template data must include {field}.'
                )
        
        return value
    
    def validate_variables(self, value):
        """Validate template variables."""
        if not isinstance(value, dict):
            raise serializers.ValidationError(
                'Variables must be a valid JSON object.'
            )
        
        # Validate variable definitions
        for var_name, var_config in value.items():
            if not isinstance(var_config, dict):
                raise serializers.ValidationError(
                    f'Variable {var_name} must be a configuration object.'
                )
            
            required_keys = ['type', 'label']
            for key in required_keys:
                if key not in var_config:
                    raise serializers.ValidationError(
                        f'Variable {var_name} must include {key}.'
                    )
        
        return value


class CreativeUploadSerializer(serializers.ModelSerializer):
    """Creative file upload serializer."""
    
    class Meta:
        model = Creative
        fields = ['primary_file']
    
    def validate_primary_file(self, value):
        """Validate uploaded file."""
        if not value:
            raise serializers.ValidationError('File is required.')
        
        # Check file size (100MB limit for uploads)
        max_size = 100 * 1024 * 1024  # 100MB
        if value.size > max_size:
            raise serializers.ValidationError(
                f'File size cannot exceed {max_size // (1024 * 1024)}MB.'
            )
        
        # Get file extension
        file_name = getattr(value, 'name', '')
        if file_name:
            ext = os.path.splitext(file_name)[1].lower()
            
            # Define allowed extensions
            allowed_extensions = {
                '.jpg', '.jpeg', '.png', '.gif', '.webp',  # Images
                '.mp4', '.avi', '.mov', '.wmv', '.flv',    # Videos
                '.mp3', '.wav', '.aac', '.ogg',           # Audio
                '.pdf', '.html', '.htm'                   # Documents
            }
            
            if ext not in allowed_extensions:
                raise serializers.ValidationError(
                    f'File extension {ext} is not supported.'
                )
        
        return value
    
    def update(self, instance, validated_data):
        """Update creative with new file."""
        # Delete old file if exists
        if instance.primary_file:
            old_file = instance.primary_file
            instance.primary_file = validated_data.get('primary_file')
            instance.creative_status = 'processing'
            instance.save()
            
            # Delete old file from storage
            if old_file and os.path.isfile(old_file.path):
                os.remove(old_file.path)
        else:
            instance.primary_file = validated_data.get('primary_file')
            instance.creative_status = 'processing'
            instance.save()
        
        return instance


class BulkCreativeSerializer(serializers.Serializer):
    """Bulk creative operations serializer."""
    
    creatives = CreativeCreateSerializer(many=True)
    campaign = serializers.PrimaryKeyRelatedField(
        queryset=Campaign.objects.filter(status='active')
    )
    
    def validate_creatives(self, value):
        """Validate creative list."""
        if not value:
            raise serializers.ValidationError('At least one creative is required.')
        
        if len(value) > 50:
            raise serializers.ValidationError('Cannot create more than 50 creatives at once.')
        
        # Check for duplicate names
        names = [creative['name'] for creative in value]
        if len(names) != len(set(names)):
            raise serializers.ValidationError('Creative names must be unique.')
        
        return value
    
    def create(self, validated_data):
        """Create multiple creatives."""
        creatives_data = validated_data['creatives']
        campaign = validated_data['campaign']
        user = self.context['request'].user
        
        creatives = []
        for creative_data in creatives_data:
            creative_data['campaign'] = campaign
            creative_data['created_by'] = user
            creative_data['updated_by'] = user
            
            creative = Creative.objects.create(**creative_data)
            creatives.append(creative)
        
        return creatives


class CreativeFormatSerializer(serializers.ModelSerializer):
    """Creative format serializer."""
    
    class Meta:
        model = CreativeFormat
        fields = [
            'id', 'name', 'width', 'height', 'aspect_ratio',
            'max_file_size', 'supported_types', 'description',
            'is_active', 'created_at'
        ]
        read_only_fields = ['id', 'created_at']
    
    def validate_supported_types(self, value):
        """Validate supported file types."""
        if not isinstance(value, list):
            raise serializers.ValidationError(
                'Supported types must be a list.'
            )
        
        valid_types = [
            'image/jpeg', 'image/png', 'image/gif', 'image/webp',
            'video/mp4', 'video/avi', 'video/mov', 'video/wmv',
            'audio/mp3', 'audio/wav', 'audio/aac',
            'application/pdf', 'text/html'
        ]
        
        for file_type in value:
            if file_type not in valid_types:
                raise serializers.ValidationError(
                    f'File type {file_type} is not supported.'
                )
        
        return value


class CreativeStatsSerializer(serializers.Serializer):
    """Creative statistics serializer."""
    
    total_creatives = serializers.IntegerField()
    pending_approval = serializers.IntegerField()
    approved = serializers.IntegerField()
    processing = serializers.IntegerField()
    rejected = serializers.IntegerField()
    
    # Performance metrics
    total_impressions = serializers.IntegerField()
    total_clicks = serializers.IntegerField()
    total_conversions = serializers.IntegerField()
    total_spend = serializers.DecimalField(max_digits=12, decimal_places=2)
    total_revenue = serializers.DecimalField(max_digits=12, decimal_places=2)
    
    # Calculated metrics
    average_ctr = serializers.FloatField()
    average_conversion_rate = serializers.FloatField()
    average_roas = serializers.FloatField()
    
    # Type distribution
    type_distribution = serializers.DictField()
    
    # Recent activity
    creatives_created_today = serializers.IntegerField()
    approvals_today = serializers.IntegerField()
    rejections_today = serializers.IntegerField()


class CreativeSearchSerializer(serializers.Serializer):
    """Creative search serializer."""
    
    query = serializers.CharField(max_length=255)
    creative_type = serializers.ChoiceField(
        choices=Creative.CREATIVE_TYPES,
        required=False
    )
    status = serializers.ChoiceField(
        choices=Creative.CREATIVE_STATUS,
        required=False
    )
    campaign = serializers.PrimaryKeyRelatedField(
        queryset=Campaign.objects.all(),
        required=False
    )
    tags = serializers.PrimaryKeyRelatedField(
        queryset=CreativeTag.objects.all(),
        many=True,
        required=False
    )
    date_from = serializers.DateField(required=False)
    date_to = serializers.DateField(required=False)
    
    def validate(self, attrs):
        """Validate search parameters."""
        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 cannot be later than date to.'
            )
        
        return attrs