"""Channels Serializers

This module contains serializers for channel management functionality.
It provides data serialization and deserialization for API operations
related to channels, zones, codecs, jingles, and time slots.

Serializers:
    - ChannelSerializer: Basic channel serialization
    - ChannelDetailSerializer: Detailed channel with relationships
    - ChannelZoneSerializer: Channel zone serialization
    - ChannelCodecSerializer: Codec configuration serialization
    - JingleSerializer: Jingle serialization
    - DayTimeSerializer: Time slot serialization
    - Nested and bulk operation serializers
    - Upload and file handling serializers

Features:
- Comprehensive field validation
- Nested relationship handling
- File upload validation
- Bulk operations support
- Custom field processing
- Statistics serialization
"""

import os
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import InMemoryUploadedFile
from mutagen import File as MutagenFile
from mutagen.mp3 import MP3
from mutagen.wave import WAVE
from mutagen.flac import FLAC
from mutagen.oggvorbis import OggVorbis
from mutagen.mp4 import MP4

from .models import Channel, ChannelZone, ChannelCodec, Jingle, DayTime
from apps.core.serializers import BaseModelSerializer


User = get_user_model()


class ChannelSerializer(BaseModelSerializer):
    """Basic serializer for Channel model.
    
    Provides standard CRUD operations with essential fields
    and basic validation.
    """
    
    total_zones = serializers.ReadOnlyField()
    total_jingles = serializers.ReadOnlyField()
    provider_display = serializers.CharField(source='get_provider_display', read_only=True)
    codec_display = serializers.CharField(source='get_default_codec_display', read_only=True)
    
    class Meta:
        model = Channel
        fields = [
            'id', 'name', 'channel_code', 'description', 'logo',
            'provider', 'provider_display', 'ftp_channel_name',
            'is_hd', 'is_4k', 'default_codec', 'codec_display',
            'audio_codec', 'bitrate', 'resolution', 'frame_rate',
            'aspect_ratio', 'language', 'region', 'time_zone',
            'epg_source', 'status', 'total_zones', 'total_jingles',
            'created_at', 'updated_at', 'created_by', 'updated_by'
        ]
        read_only_fields = ['created_at', 'updated_at', 'created_by', 'updated_by']
    
    def validate_channel_code(self, value):
        """Validate channel code uniqueness."""
        if self.instance:
            # Update case - exclude current instance
            if Channel.objects.exclude(pk=self.instance.pk).filter(channel_code=value).exists():
                raise serializers.ValidationError("Channel code must be unique.")
        else:
            # Create case
            if Channel.objects.filter(channel_code=value).exists():
                raise serializers.ValidationError("Channel code must be unique.")
        return value
    
    def validate_bitrate(self, value):
        """Validate bitrate range."""
        if value < 100 or value > 100000:
            raise serializers.ValidationError("Bitrate must be between 100 and 100000 kbps.")
        return value
    
    def validate_frame_rate(self, value):
        """Validate frame rate."""
        if value <= 0 or value > 120:
            raise serializers.ValidationError("Frame rate must be between 0.1 and 120 fps.")
        return value


class ChannelZoneSerializer(BaseModelSerializer):
    """Serializer for ChannelZone model.
    
    Handles regional zone configurations for channels.
    """
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    duration_minutes = serializers.ReadOnlyField()
    
    class Meta:
        model = ChannelZone
        fields = [
            'id', 'channel', 'channel_name', 'zone_name', 'region_name',
            'description', 'ftp_path', 'is_primary', 'broadcast_start_time',
            'broadcast_end_time', 'time_offset', 'duration_minutes',
            'status', 'created_at', 'updated_at', 'created_by', 'updated_by'
        ]
        read_only_fields = ['created_at', 'updated_at', 'created_by', 'updated_by']
    
    def validate(self, data):
        """Validate zone data."""
        # Check for duplicate region per channel
        channel = data.get('channel')
        region_name = data.get('region_name')
        
        if channel and region_name:
            queryset = ChannelZone.objects.filter(
                channel=channel,
                region_name=region_name
            )
            
            if self.instance:
                queryset = queryset.exclude(pk=self.instance.pk)
            
            if queryset.exists():
                raise serializers.ValidationError(
                    "A zone with this region already exists for this channel."
                )
        
        # Validate broadcast times
        start_time = data.get('broadcast_start_time')
        end_time = data.get('broadcast_end_time')
        
        if start_time and end_time and start_time == end_time:
            raise serializers.ValidationError(
                "Start time and end time cannot be the same."
            )
        
        return data


class ChannelCodecSerializer(BaseModelSerializer):
    """Serializer for ChannelCodec model.
    
    Handles codec configurations for different quality levels.
    """
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    quality_display = serializers.CharField(source='get_quality_level_display', read_only=True)
    video_codec_display = serializers.CharField(source='get_video_codec_display', read_only=True)
    audio_codec_display = serializers.CharField(source='get_audio_codec_display', read_only=True)
    
    class Meta:
        model = ChannelCodec
        fields = [
            'id', 'channel', 'channel_name', 'quality_level', 'quality_display',
            'video_codec', 'video_codec_display', 'audio_codec', 'audio_codec_display',
            'bitrate', 'resolution', 'frame_rate', 'audio_bitrate',
            'audio_sample_rate', 'is_default', 'status',
            'created_at', 'updated_at', 'created_by', 'updated_by'
        ]
        read_only_fields = ['created_at', 'updated_at', 'created_by', 'updated_by']
    
    def validate(self, data):
        """Validate codec configuration."""
        # Check for duplicate quality level per channel
        channel = data.get('channel')
        quality_level = data.get('quality_level')
        
        if channel and quality_level:
            queryset = ChannelCodec.objects.filter(
                channel=channel,
                quality_level=quality_level
            )
            
            if self.instance:
                queryset = queryset.exclude(pk=self.instance.pk)
            
            if queryset.exists():
                raise serializers.ValidationError(
                    "A codec configuration with this quality level already exists for this channel."
                )
        
        return data


class JingleSerializer(BaseModelSerializer):
    """Serializer for Jingle model.
    
    Handles audio jingle data with file information.
    """
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    jingle_type = serializers.ReadOnlyField()
    file_size_mb = serializers.ReadOnlyField()
    audio_format_display = serializers.CharField(source='get_audio_format_display', read_only=True)
    
    class Meta:
        model = Jingle
        fields = [
            'id', 'channel', 'channel_name', 'name', 'description',
            'audio_file', 'duration', 'file_size', 'file_size_mb',
            'audio_format', 'audio_format_display', 'sample_rate', 'bitrate',
            'is_intro', 'is_outro', 'is_transition', 'jingle_type',
            'play_order', 'status', 'created_at', 'updated_at',
            'created_by', 'updated_by'
        ]
        read_only_fields = [
            'duration', 'file_size', 'audio_format', 'sample_rate', 'bitrate',
            'created_at', 'updated_at', 'created_by', 'updated_by'
        ]
    
    def validate_audio_file(self, value):
        """Validate audio file."""
        if not value:
            return value
        
        # Check file extension
        allowed_extensions = ['mp3', 'wav', 'aac', 'flac', 'ogg']
        file_extension = os.path.splitext(value.name)[1][1:].lower()
        
        if file_extension not in allowed_extensions:
            raise serializers.ValidationError(
                f"Unsupported file format. Allowed formats: {', '.join(allowed_extensions)}"
            )
        
        # Check file size (max 50MB)
        if value.size > 50 * 1024 * 1024:
            raise serializers.ValidationError("File size cannot exceed 50MB.")
        
        return value
    
    def create(self, validated_data):
        """Create jingle with audio file analysis."""
        audio_file = validated_data.get('audio_file')
        
        if audio_file:
            # Analyze audio file
            file_info = self._analyze_audio_file(audio_file)
            validated_data.update(file_info)
        
        return super().create(validated_data)
    
    def _analyze_audio_file(self, audio_file):
        """Analyze audio file to extract metadata."""
        file_info = {
            'file_size': audio_file.size,
            'audio_format': os.path.splitext(audio_file.name)[1][1:].lower(),
        }
        
        try:
            # Save temporary file for analysis
            if isinstance(audio_file, InMemoryUploadedFile):
                # For in-memory files, we'll use default values
                file_info.update({
                    'duration': 30.0,  # Default duration
                    'sample_rate': 44100,
                    'bitrate': 128,
                })
            else:
                # For actual files, analyze with mutagen
                mutagen_file = MutagenFile(audio_file.temporary_file_path())
                if mutagen_file:
                    file_info.update({
                        'duration': mutagen_file.info.length,
                        'sample_rate': getattr(mutagen_file.info, 'sample_rate', 44100),
                        'bitrate': getattr(mutagen_file.info, 'bitrate', 128),
                    })
        except Exception:
            # If analysis fails, use defaults
            file_info.update({
                'duration': 30.0,
                'sample_rate': 44100,
                'bitrate': 128,
            })
        
        return file_info


class DayTimeSerializer(BaseModelSerializer):
    """Serializer for DayTime model.
    
    Handles time slot configurations.
    """
    
    day_display = serializers.CharField(source='get_day_of_week_display', read_only=True)
    duration_minutes = serializers.ReadOnlyField()
    
    class Meta:
        model = DayTime
        fields = [
            'id', 'name', 'description', 'start_time', 'end_time',
            'day_of_week', 'day_display', 'is_prime_time', 'is_weekend',
            'priority', 'duration_minutes', 'status',
            'created_at', 'updated_at', 'created_by', 'updated_by'
        ]
        read_only_fields = ['created_at', 'updated_at', 'created_by', 'updated_by']
    
    def validate(self, data):
        """Validate time slot data."""
        start_time = data.get('start_time')
        end_time = data.get('end_time')
        
        if start_time and end_time and start_time == end_time:
            raise serializers.ValidationError(
                "Start time and end time cannot be the same."
            )
        
        return data


# ============================================================================
# Detailed and Nested Serializers
# ============================================================================

class ChannelDetailSerializer(ChannelSerializer):
    """Detailed serializer for Channel model with related data.
    
    Includes nested zones, codecs, and jingles information.
    """
    
    zones = ChannelZoneSerializer(many=True, read_only=True)
    codecs = ChannelCodecSerializer(many=True, read_only=True)
    jingles = JingleSerializer(many=True, read_only=True)
    
    class Meta(ChannelSerializer.Meta):
        fields = ChannelSerializer.Meta.fields + ['zones', 'codecs', 'jingles']


class ChannelWithZonesSerializer(ChannelSerializer):
    """Channel serializer with zones only."""
    
    zones = ChannelZoneSerializer(many=True, read_only=True)
    
    class Meta(ChannelSerializer.Meta):
        fields = ChannelSerializer.Meta.fields + ['zones']


class ChannelStatsSerializer(serializers.Serializer):
    """Serializer for channel statistics."""
    
    total_channels = serializers.IntegerField()
    active_channels = serializers.IntegerField()
    inactive_channels = serializers.IntegerField()
    by_provider = serializers.ListField()
    hd_channels = serializers.IntegerField()
    uhd_channels = serializers.IntegerField()
    total_zones = serializers.IntegerField()
    total_jingles = serializers.IntegerField()


# ============================================================================
# Bulk Operation Serializers
# ============================================================================

class BulkChannelSerializer(serializers.Serializer):
    """Serializer for bulk channel operations."""
    
    channel_ids = serializers.ListField(
        child=serializers.IntegerField(),
        min_length=1,
        help_text="List of channel IDs to perform bulk operation on"
    )
    
    def validate_channel_ids(self, value):
        """Validate that all channel IDs exist."""
        existing_ids = set(Channel.objects.filter(id__in=value).values_list('id', flat=True))
        provided_ids = set(value)
        
        if existing_ids != provided_ids:
            missing_ids = provided_ids - existing_ids
            raise serializers.ValidationError(
                f"The following channel IDs do not exist: {list(missing_ids)}"
            )
        
        return value


class BulkJingleSerializer(serializers.Serializer):
    """Serializer for bulk jingle operations."""
    
    jingle_ids = serializers.ListField(
        child=serializers.IntegerField(),
        min_length=1,
        help_text="List of jingle IDs to perform bulk operation on"
    )
    
    def validate_jingle_ids(self, value):
        """Validate that all jingle IDs exist."""
        existing_ids = set(Jingle.objects.filter(id__in=value).values_list('id', flat=True))
        provided_ids = set(value)
        
        if existing_ids != provided_ids:
            missing_ids = provided_ids - existing_ids
            raise serializers.ValidationError(
                f"The following jingle IDs do not exist: {list(missing_ids)}"
            )
        
        return value


# ============================================================================
# Upload and File Handling Serializers
# ============================================================================

class JingleUploadSerializer(serializers.ModelSerializer):
    """Specialized serializer for jingle file uploads."""
    
    class Meta:
        model = Jingle
        fields = [
            'channel', 'name', 'description', 'audio_file',
            'is_intro', 'is_outro', 'is_transition', 'play_order'
        ]
    
    def validate_audio_file(self, value):
        """Validate uploaded audio file."""
        if not value:
            raise serializers.ValidationError("Audio file is required.")
        
        # Check file extension
        allowed_extensions = ['mp3', 'wav', 'aac', 'flac', 'ogg']
        file_extension = os.path.splitext(value.name)[1][1:].lower()
        
        if file_extension not in allowed_extensions:
            raise serializers.ValidationError(
                f"Unsupported file format. Allowed formats: {', '.join(allowed_extensions)}"
            )
        
        # Check file size (max 50MB)
        if value.size > 50 * 1024 * 1024:
            raise serializers.ValidationError("File size cannot exceed 50MB.")
        
        return value
    
    def create(self, validated_data):
        """Create jingle with automatic file analysis."""
        audio_file = validated_data['audio_file']
        
        # Analyze audio file
        file_info = self._analyze_audio_file(audio_file)
        validated_data.update(file_info)
        
        return super().create(validated_data)
    
    def _analyze_audio_file(self, audio_file):
        """Analyze audio file to extract metadata."""
        file_info = {
            'file_size': audio_file.size,
            'audio_format': os.path.splitext(audio_file.name)[1][1:].lower(),
            'duration': 30.0,  # Default
            'sample_rate': 44100,  # Default
            'bitrate': 128,  # Default
        }
        
        try:
            # For uploaded files, try to analyze
            if hasattr(audio_file, 'temporary_file_path'):
                mutagen_file = MutagenFile(audio_file.temporary_file_path())
                if mutagen_file and hasattr(mutagen_file, 'info'):
                    file_info.update({
                        'duration': getattr(mutagen_file.info, 'length', 30.0),
                        'sample_rate': getattr(mutagen_file.info, 'sample_rate', 44100),
                        'bitrate': getattr(mutagen_file.info, 'bitrate', 128),
                    })
        except Exception:
            # If analysis fails, keep defaults
            pass
        
        return file_info


class ChannelLogoUploadSerializer(serializers.ModelSerializer):
    """Specialized serializer for channel logo uploads."""
    
    class Meta:
        model = Channel
        fields = ['logo']
    
    def validate_logo(self, value):
        """Validate uploaded logo file."""
        if not value:
            return value
        
        # Check file extension
        allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'svg']
        file_extension = os.path.splitext(value.name)[1][1:].lower()
        
        if file_extension not in allowed_extensions:
            raise serializers.ValidationError(
                f"Unsupported image format. Allowed formats: {', '.join(allowed_extensions)}"
            )
        
        # Check file size (max 5MB)
        if value.size > 5 * 1024 * 1024:
            raise serializers.ValidationError("Image size cannot exceed 5MB.")
        
        return value


# ============================================================================
# Summary and List Serializers
# ============================================================================

class ChannelSummarySerializer(serializers.ModelSerializer):
    """Lightweight serializer for channel summaries and lists."""
    
    provider_display = serializers.CharField(source='get_provider_display', read_only=True)
    
    class Meta:
        model = Channel
        fields = [
            'id', 'name', 'channel_code', 'provider', 'provider_display',
            'is_hd', 'is_4k', 'status'
        ]


class JingleSummarySerializer(serializers.ModelSerializer):
    """Lightweight serializer for jingle summaries."""
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    jingle_type = serializers.ReadOnlyField()
    
    class Meta:
        model = Jingle
        fields = [
            'id', 'name', 'channel', 'channel_name', 'duration',
            'jingle_type', 'play_order', 'status'
        ]