from rest_framework import serializers
from django.utils import timezone
from .models import Codec, Zone, Channel, ChannelZone, Jingle, Show, EPGEntry


class CodecSerializer(serializers.ModelSerializer):
    """
    Serializer for Codec model.
    
    Provides JSON representation of codec data with
    validation and computed fields.
    """
    codec_type_display = serializers.CharField(source='get_codec_type_display', read_only=True)
    bitrate_range = serializers.SerializerMethodField()
    
    class Meta:
        model = Codec
        fields = [
            'id', 'name', 'codec_type', 'codec_type_display',
            'description', 'mime_type', 'bitrate_min', 'bitrate_max',
            'bitrate_range', 'is_active', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_bitrate_range(self, obj):
        """
        Get formatted bitrate range string.
        
        Args:
            obj: Codec instance
        
        Returns:
            str: Formatted bitrate range or None
        """
        if obj.bitrate_min and obj.bitrate_max:
            return f"{obj.bitrate_min} - {obj.bitrate_max} kbps"
        elif obj.bitrate_min:
            return f"≥ {obj.bitrate_min} kbps"
        elif obj.bitrate_max:
            return f"≤ {obj.bitrate_max} kbps"
        return None
    
    def validate(self, data):
        """
        Validate codec data.
        
        Args:
            data: Dictionary of field values
        
        Returns:
            dict: Validated data
        
        Raises:
            ValidationError: If validation fails
        """
        bitrate_min = data.get('bitrate_min')
        bitrate_max = data.get('bitrate_max')
        
        if bitrate_min and bitrate_max and bitrate_max <= bitrate_min:
            raise serializers.ValidationError(
                'Maximum bitrate must be greater than minimum bitrate.'
            )
        
        return data


class ZoneSerializer(serializers.ModelSerializer):
    """
    Serializer for Zone model.
    
    Provides JSON representation of distribution zone data.
    """
    channels_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Zone
        fields = [
            'id', 'name', 'code', 'description', 'timezone',
            'is_active', 'channels_count', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_channels_count(self, obj):
        """
        Get the number of active channels in this zone.
        
        Args:
            obj: Zone instance
        
        Returns:
            int: Number of active channels
        """
        return obj.zone_channels.filter(is_active=True).count()


class ChannelZoneSerializer(serializers.ModelSerializer):
    """
    Serializer for ChannelZone model.
    
    Provides JSON representation of channel-zone configurations.
    """
    zone_name = serializers.CharField(source='zone.name', read_only=True)
    zone_code = serializers.CharField(source='zone.code', read_only=True)
    video_codec_name = serializers.CharField(source='video_codec.name', read_only=True)
    audio_codec_name = serializers.CharField(source='audio_codec.name', read_only=True)
    container_format_name = serializers.CharField(source='container_format.name', read_only=True)
    resolution_display = serializers.CharField(read_only=True)
    
    class Meta:
        model = ChannelZone
        fields = [
            'id', 'channel', 'zone', 'zone_name', 'zone_code',
            'video_codec', 'video_codec_name', 'audio_codec', 'audio_codec_name',
            'container_format', 'container_format_name', 'bitrate',
            'resolution_width', 'resolution_height', 'resolution_display',
            'frame_rate', 'is_active', 'start_date', 'end_date',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate(self, data):
        """
        Validate channel-zone configuration.
        
        Args:
            data: Dictionary of field values
        
        Returns:
            dict: Validated data
        
        Raises:
            ValidationError: If validation fails
        """
        start_date = data.get('start_date')
        end_date = data.get('end_date')
        
        if start_date and end_date and end_date <= start_date:
            raise serializers.ValidationError(
                'End date must be after start date.'
            )
        
        return data


class JingleSerializer(serializers.ModelSerializer):
    """
    Serializer for Jingle model.
    
    Provides JSON representation of jingle data with file information.
    """
    jingle_type_display = serializers.CharField(source='get_jingle_type_display', read_only=True)
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    has_audio = serializers.SerializerMethodField()
    has_video = serializers.SerializerMethodField()
    duration_display = serializers.SerializerMethodField()
    
    class Meta:
        model = Jingle
        fields = [
            'id', 'name', 'jingle_type', 'jingle_type_display',
            'channel', 'channel_name', 'audio_file', 'video_file',
            'has_audio', 'has_video', 'duration', 'duration_display',
            'description', 'is_active', 'priority',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_has_audio(self, obj):
        """
        Check if jingle has audio file.
        
        Args:
            obj: Jingle instance
        
        Returns:
            bool: True if audio file exists
        """
        return bool(obj.audio_file)
    
    def get_has_video(self, obj):
        """
        Check if jingle has video file.
        
        Args:
            obj: Jingle instance
        
        Returns:
            bool: True if video file exists
        """
        return bool(obj.video_file)
    
    def get_duration_display(self, obj):
        """
        Get formatted duration string.
        
        Args:
            obj: Jingle instance
        
        Returns:
            str: Formatted duration
        """
        if obj.duration:
            total_seconds = int(obj.duration.total_seconds())
            hours = total_seconds // 3600
            minutes = (total_seconds % 3600) // 60
            seconds = total_seconds % 60
            
            if hours > 0:
                return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
            else:
                return f"{minutes:02d}:{seconds:02d}"
        return None


class ShowSerializer(serializers.ModelSerializer):
    """
    Serializer for Show model.
    
    Provides JSON representation of TV show data with metadata.
    """
    show_type_display = serializers.CharField(source='get_show_type_display', read_only=True)
    content_rating_display = serializers.CharField(source='get_content_rating_display', read_only=True)
    epg_entries_count = serializers.SerializerMethodField()
    duration_display = serializers.SerializerMethodField()
    
    class Meta:
        model = Show
        fields = [
            'id', 'title', 'slug', 'show_type', 'show_type_display',
            'description', 'short_description', 'poster', 'thumbnail',
            'content_rating', 'content_rating_display', 'language',
            'country', 'year', 'duration', 'duration_display',
            'genre', 'cast', 'director', 'producer', 'imdb_id',
            'is_active', 'epg_entries_count', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'slug', 'created_at', 'updated_at']
    
    def get_epg_entries_count(self, obj):
        """
        Get the number of EPG entries for this show.
        
        Args:
            obj: Show instance
        
        Returns:
            int: Number of EPG entries
        """
        return obj.epg_entries.count()
    
    def get_duration_display(self, obj):
        """
        Get formatted duration string.
        
        Args:
            obj: Show instance
        
        Returns:
            str: Formatted duration or None
        """
        if obj.duration:
            total_seconds = int(obj.duration.total_seconds())
            hours = total_seconds // 3600
            minutes = (total_seconds % 3600) // 60
            
            if hours > 0:
                return f"{hours}h {minutes}m"
            else:
                return f"{minutes}m"
        return None


class ChannelSerializer(serializers.ModelSerializer):
    """
    Serializer for Channel model.
    
    Provides JSON representation of channel data with related information.
    """
    channel_type_display = serializers.CharField(source='get_channel_type_display', read_only=True)
    content_rating_display = serializers.CharField(source='get_content_rating_display', read_only=True)
    zones_count = serializers.SerializerMethodField()
    jingles_count = serializers.SerializerMethodField()
    active_zones = ZoneSerializer(many=True, read_only=True)
    channel_zones = ChannelZoneSerializer(many=True, read_only=True)
    
    class Meta:
        model = Channel
        fields = [
            'id', 'name', 'slug', 'call_sign', 'channel_number',
            'channel_type', 'channel_type_display', 'description',
            'logo', 'website', 'content_rating', 'content_rating_display',
            'language', 'country', 'is_active', 'is_hd', 'is_4k',
            'launch_date', 'zones_count', 'jingles_count',
            'active_zones', 'channel_zones', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'slug', 'created_at', 'updated_at']
    
    def get_zones_count(self, obj):
        """
        Get the number of active zones for this channel.
        
        Args:
            obj: Channel instance
        
        Returns:
            int: Number of active zones
        """
        return obj.active_zones_count
    
    def get_jingles_count(self, obj):
        """
        Get the number of jingles for this channel.
        
        Args:
            obj: Channel instance
        
        Returns:
            int: Number of jingles
        """
        return obj.total_jingles_count


class EPGEntrySerializer(serializers.ModelSerializer):
    """
    Serializer for EPGEntry model.
    
    Provides JSON representation of EPG entries with show and channel data.
    """
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    show_title = serializers.CharField(source='show.title', read_only=True)
    show_type = serializers.CharField(source='show.show_type', read_only=True)
    duration_display = serializers.SerializerMethodField()
    is_currently_airing = serializers.BooleanField(read_only=True)
    episode_info = serializers.SerializerMethodField()
    
    class Meta:
        model = EPGEntry
        fields = [
            'id', 'channel', 'channel_name', 'show', 'show_title', 'show_type',
            'start_time', 'end_time', 'duration_display', 'episode_title',
            'episode_number', 'season_number', 'episode_description',
            'episode_info', 'is_premiere', 'is_finale', 'is_repeat',
            'is_live', 'is_currently_airing', 'audio_language',
            'subtitle_language', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_duration_display(self, obj):
        """
        Get formatted duration string.
        
        Args:
            obj: EPGEntry instance
        
        Returns:
            str: Formatted duration
        """
        duration = obj.duration
        total_seconds = int(duration.total_seconds())
        hours = total_seconds // 3600
        minutes = (total_seconds % 3600) // 60
        
        if hours > 0:
            return f"{hours}h {minutes}m"
        else:
            return f"{minutes}m"
    
    def get_episode_info(self, obj):
        """
        Get formatted episode information.
        
        Args:
            obj: EPGEntry instance
        
        Returns:
            str: Formatted episode info or None
        """
        info_parts = []
        
        if obj.season_number:
            info_parts.append(f"S{obj.season_number}")
        
        if obj.episode_number:
            info_parts.append(f"E{obj.episode_number}")
        
        if obj.episode_title:
            info_parts.append(obj.episode_title)
        
        return ' - '.join(info_parts) if info_parts else None
    
    def validate(self, data):
        """
        Validate EPG entry data.
        
        Args:
            data: Dictionary of field values
        
        Returns:
            dict: Validated data
        
        Raises:
            ValidationError: If validation fails
        """
        start_time = data.get('start_time')
        end_time = data.get('end_time')
        
        if start_time and end_time and end_time <= start_time:
            raise serializers.ValidationError(
                'End time must be after start time.'
            )
        
        # Check for scheduling conflicts
        channel = data.get('channel')
        if channel and start_time and end_time:
            conflicting_entries = EPGEntry.objects.filter(
                channel=channel,
                start_time__lt=end_time,
                end_time__gt=start_time
            )
            
            # Exclude current instance if updating
            if self.instance:
                conflicting_entries = conflicting_entries.exclude(pk=self.instance.pk)
            
            if conflicting_entries.exists():
                conflict = conflicting_entries.first()
                raise serializers.ValidationError(
                    f'Schedule conflict with "{conflict.show.title}" '
                    f'({conflict.start_time.strftime("%Y-%m-%d %H:%M")} - '
                    f'{conflict.end_time.strftime("%H:%M")})'
                )
        
        return data


class ChannelSummarySerializer(serializers.ModelSerializer):
    """
    Lightweight serializer for Channel model.
    
    Provides minimal channel data for lists and dropdowns.
    """
    channel_type_display = serializers.CharField(source='get_channel_type_display', read_only=True)
    
    class Meta:
        model = Channel
        fields = [
            'id', 'name', 'call_sign', 'channel_number',
            'channel_type', 'channel_type_display', 'logo',
            'is_active', 'is_hd', 'is_4k'
        ]


class ShowSummarySerializer(serializers.ModelSerializer):
    """
    Lightweight serializer for Show model.
    
    Provides minimal show data for lists and dropdowns.
    """
    show_type_display = serializers.CharField(source='get_show_type_display', read_only=True)
    
    class Meta:
        model = Show
        fields = [
            'id', 'title', 'show_type', 'show_type_display',
            'content_rating', 'year', 'poster', 'is_active'
        ]


class EPGCalendarSerializer(serializers.ModelSerializer):
    """
    Specialized serializer for EPG calendar views.
    
    Provides data formatted for calendar display components.
    """
    title = serializers.SerializerMethodField()
    start = serializers.DateTimeField(source='start_time')
    end = serializers.DateTimeField(source='end_time')
    backgroundColor = serializers.SerializerMethodField()
    borderColor = serializers.SerializerMethodField()
    extendedProps = serializers.SerializerMethodField()
    
    class Meta:
        model = EPGEntry
        fields = [
            'id', 'title', 'start', 'end',
            'backgroundColor', 'borderColor', 'extendedProps'
        ]
    
    def get_title(self, obj):
        """
        Get formatted title for calendar display.
        
        Args:
            obj: EPGEntry instance
        
        Returns:
            str: Formatted title
        """
        return f"{obj.channel.name}: {obj.show.title}"
    
    def get_backgroundColor(self, obj):
        """
        Get background color based on entry properties.
        
        Args:
            obj: EPGEntry instance
        
        Returns:
            str: CSS color value
        """
        if obj.is_live:
            return '#dc3545'  # Red for live
        elif obj.is_premiere:
            return '#ffc107'  # Yellow for premiere
        elif obj.is_repeat:
            return '#6c757d'  # Gray for repeat
        else:
            return '#007bff'  # Blue for regular
    
    def get_borderColor(self, obj):
        """
        Get border color (same as background for consistency).
        
        Args:
            obj: EPGEntry instance
        
        Returns:
            str: CSS color value
        """
        return self.get_backgroundColor(obj)
    
    def get_extendedProps(self, obj):
        """
        Get extended properties for calendar events.
        
        Args:
            obj: EPGEntry instance
        
        Returns:
            dict: Extended properties
        """
        return {
            'channel': obj.channel.name,
            'show': obj.show.title,
            'episode_title': obj.episode_title or '',
            'is_live': obj.is_live,
            'is_premiere': obj.is_premiere,
            'is_repeat': obj.is_repeat,
            'content_rating': obj.show.content_rating,
            'show_type': obj.show.show_type,
        }