"""Serializers for adspots app.

This module provides DRF serializers for:
- Adspot: Advertising spot serialization
- Avail: Availability window serialization
- Window: Time window serialization
- AdspotInAvail: Adspot placement serialization
- Pending: Pending creative serialization
"""

from rest_framework import serializers
from django.contrib.auth import get_user_model

from .models import Adspot, Avail, Window, AdspotInAvail, Pending
from apps.campaigns.serializers import CampaignBasicSerializer
from apps.advertisers.serializers import BrandBasicSerializer
from apps.channels.serializers import ChannelBasicSerializer


User = get_user_model()


class AdspotSerializer(serializers.ModelSerializer):
    """Basic serializer for Adspot model."""
    
    campaign_name = serializers.CharField(source='campaign.name', read_only=True)
    brand_name = serializers.CharField(source='brand.name', read_only=True)
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    file_size_display = serializers.SerializerMethodField()
    duration_seconds = serializers.SerializerMethodField()
    
    class Meta:
        model = Adspot
        fields = [
            'id',
            'uuid',
            'name',
            'campaign',
            'campaign_name',
            'brand',
            'brand_name',
            'channel',
            'channel_name',
            'creative_id',
            'duration',
            'duration_seconds',
            'filename',
            'file_size',
            'file_size_display',
            'format',
            'resolution',
            'bitrate',
            'is_processed',
            'processing_status',
            'status',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'id',
            'uuid',
            'file_size',
            'filename',
            'is_processed',
            'processing_status',
            'created_at',
            'updated_at',
        ]
    
    def get_file_size_display(self, obj):
        """Return human readable file size."""
        if obj.file_size:
            if obj.file_size < 1024:
                return f"{obj.file_size} B"
            elif obj.file_size < 1024 * 1024:
                return f"{obj.file_size / 1024:.1f} KB"
            elif obj.file_size < 1024 * 1024 * 1024:
                return f"{obj.file_size / (1024 * 1024):.1f} MB"
            else:
                return f"{obj.file_size / (1024 * 1024 * 1024):.1f} GB"
        return None
    
    def get_duration_seconds(self, obj):
        """Convert duration string to seconds."""
        if obj.duration:
            try:
                # Assuming format is HH:MM:SS or MM:SS
                parts = obj.duration.split(':')
                if len(parts) == 3:
                    hours, minutes, seconds = map(int, parts)
                    return hours * 3600 + minutes * 60 + seconds
                elif len(parts) == 2:
                    minutes, seconds = map(int, parts)
                    return minutes * 60 + seconds
                else:
                    return int(parts[0])
            except (ValueError, IndexError):
                return None
        return None


class AdspotCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating Adspot instances."""
    
    class Meta:
        model = Adspot
        fields = [
            'name',
            'campaign',
            'brand',
            'channel',
            'original_file',
            'creative_id',
            'vast_url',
            'status',
        ]
    
    def validate_original_file(self, value):
        """Validate uploaded file."""
        if value:
            # Check file size (max 500MB)
            max_size = 500 * 1024 * 1024  # 500MB
            if value.size > max_size:
                raise serializers.ValidationError(
                    f"File size too large. Maximum size is {max_size / (1024 * 1024):.0f}MB."
                )
            
            # Check file extension
            allowed_extensions = [
                'mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv', 'ts',
                'mp3', 'wav', 'aac'
            ]
            file_extension = value.name.split('.')[-1].lower()
            if file_extension not in allowed_extensions:
                raise serializers.ValidationError(
                    f"File type '{file_extension}' not allowed. "
                    f"Allowed types: {', '.join(allowed_extensions)}"
                )
        
        return value


class AdspotDetailSerializer(serializers.ModelSerializer):
    """Detailed serializer for Adspot model."""
    
    campaign = CampaignBasicSerializer(read_only=True)
    brand = BrandBasicSerializer(read_only=True)
    channel = ChannelBasicSerializer(read_only=True)
    file_size_display = serializers.SerializerMethodField()
    duration_seconds = serializers.SerializerMethodField()
    original_file_url = serializers.SerializerMethodField()
    encoded_file_url = serializers.SerializerMethodField()
    analytics = serializers.SerializerMethodField()
    placements = serializers.SerializerMethodField()
    
    class Meta:
        model = Adspot
        fields = [
            'id',
            'uuid',
            'name',
            'campaign',
            'brand',
            'channel',
            'original_file',
            'original_file_url',
            'encoded_file',
            'encoded_file_url',
            'duration',
            'duration_seconds',
            'filename',
            'creative_id',
            'vast_url',
            'file_size',
            'file_size_display',
            'format',
            'resolution',
            'bitrate',
            'frame_rate',
            'audio_codec',
            'video_codec',
            'md5_hash',
            'is_processed',
            'processing_status',
            'error_message',
            'status',
            'analytics',
            'placements',
            'created_at',
            'updated_at',
            'created_by',
            'updated_by',
        ]
        read_only_fields = [
            'id',
            'uuid',
            'file_size',
            'filename',
            'format',
            'resolution',
            'bitrate',
            'frame_rate',
            'audio_codec',
            'video_codec',
            'md5_hash',
            'is_processed',
            'processing_status',
            'error_message',
            'created_at',
            'updated_at',
            'created_by',
            'updated_by',
        ]
    
    def get_file_size_display(self, obj):
        """Return human readable file size."""
        if obj.file_size:
            if obj.file_size < 1024:
                return f"{obj.file_size} B"
            elif obj.file_size < 1024 * 1024:
                return f"{obj.file_size / 1024:.1f} KB"
            elif obj.file_size < 1024 * 1024 * 1024:
                return f"{obj.file_size / (1024 * 1024):.1f} MB"
            else:
                return f"{obj.file_size / (1024 * 1024 * 1024):.1f} GB"
        return None
    
    def get_duration_seconds(self, obj):
        """Convert duration string to seconds."""
        if obj.duration:
            try:
                parts = obj.duration.split(':')
                if len(parts) == 3:
                    hours, minutes, seconds = map(int, parts)
                    return hours * 3600 + minutes * 60 + seconds
                elif len(parts) == 2:
                    minutes, seconds = map(int, parts)
                    return minutes * 60 + seconds
                else:
                    return int(parts[0])
            except (ValueError, IndexError):
                return None
        return None
    
    def get_original_file_url(self, obj):
        """Return original file URL."""
        if obj.original_file:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.original_file.url)
            return obj.original_file.url
        return None
    
    def get_encoded_file_url(self, obj):
        """Return encoded file URL."""
        if obj.encoded_file:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.encoded_file.url)
            return obj.encoded_file.url
        return None
    
    def get_analytics(self, obj):
        """Return analytics data."""
        return obj.get_impressions()
    
    def get_placements(self, obj):
        """Return placement information."""
        placements = obj.avail_placements.all()
        return AdspotInAvailSerializer(placements, many=True).data


class AvailSerializer(serializers.ModelSerializer):
    """Serializer for Avail model."""
    
    window_info = serializers.SerializerMethodField()
    adspot_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Avail
        fields = [
            'id',
            'uuid',
            'window',
            'window_info',
            'avail_start',
            'avail_in_window',
            'adspot_count',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'id',
            'uuid',
            'created_at',
            'updated_at',
        ]
    
    def get_window_info(self, obj):
        """Return window information."""
        if obj.window:
            return {
                'id': obj.window.id,
                'window_start': obj.window.window_start,
                'window_end': obj.window.window_end,
                'window_duration': obj.window.window_duration,
            }
        return None
    
    def get_adspot_count(self, obj):
        """Return count of adspots in this avail."""
        return obj.adspot_placements.count()


class WindowSerializer(serializers.ModelSerializer):
    """Serializer for Window model."""
    
    playlist_info = serializers.SerializerMethodField()
    avail_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Window
        fields = [
            'id',
            'uuid',
            'playlist',
            'playlist_info',
            'window_start',
            'window_end',
            'window_duration',
            'avail_count',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'id',
            'uuid',
            'created_at',
            'updated_at',
        ]
    
    def get_playlist_info(self, obj):
        """Return playlist information."""
        if obj.playlist:
            return {
                'id': obj.playlist.id,
                'name': getattr(obj.playlist, 'name', 'Unknown'),
            }
        return None
    
    def get_avail_count(self, obj):
        """Return count of avails in this window."""
        return obj.avails.count()


class AdspotInAvailSerializer(serializers.ModelSerializer):
    """Serializer for AdspotInAvail model."""
    
    avail_info = serializers.SerializerMethodField()
    adspot_info = serializers.SerializerMethodField()
    
    class Meta:
        model = AdspotInAvail
        fields = [
            'id',
            'uuid',
            'avail',
            'avail_info',
            'adspot',
            'adspot_info',
            'position_in_avail',
            'traffic_id',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'id',
            'uuid',
            'created_at',
            'updated_at',
        ]
    
    def get_avail_info(self, obj):
        """Return avail information."""
        if obj.avail:
            return {
                'id': obj.avail.id,
                'avail_start': obj.avail.avail_start,
                'avail_in_window': obj.avail.avail_in_window,
            }
        return None
    
    def get_adspot_info(self, obj):
        """Return adspot information."""
        if obj.adspot:
            return {
                'id': obj.adspot.id,
                'name': obj.adspot.name,
                'creative_id': obj.adspot.creative_id,
                'duration': obj.adspot.duration,
                'format': obj.adspot.format,
                'processing_status': obj.adspot.processing_status,
            }
        return None
    
    def validate(self, data):
        """Validate placement data."""
        avail = data.get('avail')
        position = data.get('position_in_avail')
        
        # Check if position is already taken (for create/update)
        if avail and position is not None:
            existing = AdspotInAvail.objects.filter(
                avail=avail,
                position_in_avail=position
            )
            
            # Exclude current instance for updates
            if self.instance:
                existing = existing.exclude(id=self.instance.id)
            
            if existing.exists():
                raise serializers.ValidationError({
                    'position_in_avail': 'This position is already taken in the avail.'
                })
        
        return data


class PendingSerializer(serializers.ModelSerializer):
    """Serializer for Pending model."""
    
    class Meta:
        model = Pending
        fields = [
            'id',
            'uuid',
            'creative_id',
            'url',
            'duration',
            'status',
            'error_message',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'id',
            'uuid',
            'created_at',
            'updated_at',
        ]
    
    def validate_url(self, value):
        """Validate URL format."""
        if value:
            # Basic URL validation
            if not value.startswith(('http://', 'https://')):
                raise serializers.ValidationError(
                    "URL must start with http:// or https://"
                )
        return value
    
    def validate_creative_id(self, value):
        """Validate creative ID uniqueness for pending status."""
        if value:
            # Check if creative_id already exists in pending status
            existing = Pending.objects.filter(
                creative_id=value,
                status='pending'
            )
            
            # Exclude current instance for updates
            if self.instance:
                existing = existing.exclude(id=self.instance.id)
            
            if existing.exists():
                raise serializers.ValidationError(
                    "A pending creative with this ID already exists."
                )
        
        return value


# Basic serializers for use in other apps

class AdspotBasicSerializer(serializers.ModelSerializer):
    """Basic serializer for Adspot model (for use in other apps)."""
    
    class Meta:
        model = Adspot
        fields = [
            'id',
            'name',
            'creative_id',
            'duration',
            'format',
            'processing_status',
        ]


class AvailBasicSerializer(serializers.ModelSerializer):
    """Basic serializer for Avail model (for use in other apps)."""
    
    class Meta:
        model = Avail
        fields = [
            'id',
            'avail_start',
            'avail_in_window',
        ]


class WindowBasicSerializer(serializers.ModelSerializer):
    """Basic serializer for Window model (for use in other apps)."""
    
    class Meta:
        model = Window
        fields = [
            'id',
            'window_start',
            'window_end',
            'window_duration',
        ]