"""Serializers for Jingles app."""

from rest_framework import serializers
from django.contrib.auth.models import User
from django.utils import timezone

from .models import (
    JingleCategory,
    JingleType,
    Jingle,
    JinglePlaylist,
    JinglePlaylistItem,
    JingleSchedule,
)
from apps.channels.models import Channel


class UserBasicSerializer(serializers.ModelSerializer):
    """Basic user serializer for nested representations."""
    
    class Meta:
        model = User
        fields = ['id', 'username', 'first_name', 'last_name', 'email']
        read_only_fields = ['id', 'username', 'first_name', 'last_name', 'email']


class ChannelBasicSerializer(serializers.ModelSerializer):
    """Basic channel serializer for nested representations."""
    
    class Meta:
        model = Channel
        fields = ['id', 'name', 'code']
        read_only_fields = ['id', 'name', 'code']


class JingleCategorySerializer(serializers.ModelSerializer):
    """Serializer for JingleCategory model."""
    
    jingle_count = serializers.SerializerMethodField()
    
    class Meta:
        model = JingleCategory
        fields = [
            'id', 'name', 'description', 'color_code',
            'sort_order', 'is_active', 'jingle_count',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at', 'jingle_count']
    
    def get_jingle_count(self, obj):
        """Get the number of jingles in this category."""
        return obj.jingles.filter(is_deleted=False).count()
    
    def validate_color_code(self, value):
        """Validate color code format."""
        if not value.startswith('#') or len(value) != 7:
            raise serializers.ValidationError(
                "Color code must be in hex format (e.g., #007bff)"
            )
        return value


class JingleTypeSerializer(serializers.ModelSerializer):
    """Serializer for JingleType model."""
    
    usage_display = serializers.CharField(source='get_usage_display', read_only=True)
    jingle_count = serializers.SerializerMethodField()
    default_duration_display = serializers.SerializerMethodField()
    
    class Meta:
        model = JingleType
        fields = [
            'id', 'name', 'usage', 'usage_display', 'description',
            'default_duration', 'default_duration_display',
            'is_active', 'jingle_count', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'usage_display', 'default_duration_display',
            'jingle_count', 'created_at', 'updated_at'
        ]
    
    def get_jingle_count(self, obj):
        """Get the number of jingles of this type."""
        return obj.jingles.filter(is_deleted=False).count()
    
    def get_default_duration_display(self, obj):
        """Get human-readable default duration."""
        if obj.default_duration:
            minutes, seconds = divmod(obj.default_duration, 60)
            return f"{minutes:02d}:{seconds:02d}"
        return None


class JingleSerializer(serializers.ModelSerializer):
    """Basic serializer for Jingle model."""
    
    channel = ChannelBasicSerializer(read_only=True)
    channel_id = serializers.PrimaryKeyRelatedField(
        queryset=Channel.objects.filter(is_active=True),
        source='channel',
        write_only=True
    )
    category = JingleCategorySerializer(read_only=True)
    category_id = serializers.PrimaryKeyRelatedField(
        queryset=JingleCategory.objects.filter(is_active=True),
        source='category',
        write_only=True,
        required=False,
        allow_null=True
    )
    jingle_type = JingleTypeSerializer(read_only=True)
    jingle_type_id = serializers.PrimaryKeyRelatedField(
        queryset=JingleType.objects.filter(is_active=True),
        source='jingle_type',
        write_only=True,
        required=False,
        allow_null=True
    )
    
    # Display fields
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    quality_display = serializers.CharField(source='get_quality_display', read_only=True)
    duration_display = serializers.SerializerMethodField()
    file_size_display = serializers.SerializerMethodField()
    file_url = serializers.SerializerMethodField()
    is_video = serializers.SerializerMethodField()
    is_audio = serializers.SerializerMethodField()
    is_available = serializers.SerializerMethodField()
    tags_list = serializers.SerializerMethodField()
    
    class Meta:
        model = Jingle
        fields = [
            'id', 'name', 'description', 'channel', 'channel_id',
            'category', 'category_id', 'jingle_type', 'jingle_type_id',
            'file', 'file_url', 'file_size', 'file_size_display',
            'file_format', 'duration_seconds', 'duration_display',
            'status', 'status_display', 'quality', 'quality_display',
            'is_active', 'priority', 'play_count', 'last_played',
            'start_date', 'end_date', 'tags', 'tags_list',
            'is_video', 'is_audio', 'is_available',
            'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'file_size', 'file_format', 'md5_hash',
            'duration_seconds', 'bitrate', 'sample_rate', 'channels',
            'codec', 'width', 'height', 'frame_rate',
            'play_count', 'last_played', 'uploaded_by',
            'approved_by', 'approved_at', 'created_at', 'updated_at',
            'status_display', 'quality_display', 'duration_display',
            'file_size_display', 'file_url', 'is_video', 'is_audio',
            'is_available', 'tags_list'
        ]
    
    def get_duration_display(self, obj):
        """Get human-readable duration."""
        return obj.get_duration_display()
    
    def get_file_size_display(self, obj):
        """Get human-readable file size."""
        return obj.get_file_size_display()
    
    def get_file_url(self, obj):
        """Get file URL."""
        return obj.get_file_url()
    
    def get_is_video(self, obj):
        """Check if jingle is video."""
        return obj.is_video()
    
    def get_is_audio(self, obj):
        """Check if jingle is audio."""
        return obj.is_audio()
    
    def get_is_available(self, obj):
        """Check if jingle is available for use."""
        return obj.is_available()
    
    def get_tags_list(self, obj):
        """Get tags as a list."""
        return obj.get_tags_list()
    
    def validate_file(self, value):
        """Validate uploaded file."""
        if value:
            # Check file size (max 100MB)
            max_size = 100 * 1024 * 1024  # 100MB
            if value.size > max_size:
                raise serializers.ValidationError(
                    "File size cannot exceed 100MB"
                )
            
            # Check file extension
            allowed_extensions = [
                'mp3', 'wav', 'aac', 'ogg', 'flac',
                'mp4', 'mov', 'avi', 'mkv', 'webm'
            ]
            file_extension = value.name.split('.')[-1].lower()
            if file_extension not in allowed_extensions:
                raise serializers.ValidationError(
                    f"File type '{file_extension}' is not supported. "
                    f"Allowed types: {', '.join(allowed_extensions)}"
                )
        
        return value
    
    def validate(self, data):
        """Validate the entire object."""
        # Check date range
        start_date = data.get('start_date')
        end_date = data.get('end_date')
        
        if start_date and end_date and start_date > end_date:
            raise serializers.ValidationError(
                "Start date cannot be after end date"
            )
        
        return data


class JingleDetailSerializer(JingleSerializer):
    """Detailed serializer for Jingle model."""
    
    uploaded_by = UserBasicSerializer(read_only=True)
    approved_by = UserBasicSerializer(read_only=True)
    resolution_display = serializers.SerializerMethodField()
    playlists = serializers.SerializerMethodField()
    
    class Meta(JingleSerializer.Meta):
        fields = JingleSerializer.Meta.fields + [
            'bitrate', 'sample_rate', 'channels', 'codec',
            'width', 'height', 'frame_rate', 'resolution_display',
            'md5_hash', 'uploaded_by', 'approved_by', 'approved_at',
            'notes', 'metadata', 'playlists'
        ]
    
    def get_resolution_display(self, obj):
        """Get video resolution display."""
        return obj.get_resolution_display()
    
    def get_playlists(self, obj):
        """Get playlists containing this jingle."""
        playlists = obj.playlists.filter(is_active=True)
        return [{
            'id': playlist.id,
            'name': playlist.name,
            'channel': playlist.channel.name
        } for playlist in playlists]


class JinglePlaylistItemSerializer(serializers.ModelSerializer):
    """Serializer for JinglePlaylistItem model."""
    
    jingle = JingleSerializer(read_only=True)
    jingle_id = serializers.PrimaryKeyRelatedField(
        queryset=Jingle.objects.filter(
            is_active=True,
            status='approved',
            is_deleted=False
        ),
        source='jingle',
        write_only=True
    )
    is_available = serializers.SerializerMethodField()
    
    class Meta:
        model = JinglePlaylistItem
        fields = [
            'id', 'jingle', 'jingle_id', 'order', 'is_active',
            'start_date', 'end_date', 'play_count', 'last_played',
            'is_available', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'play_count', 'last_played', 'is_available',
            'created_at', 'updated_at'
        ]
    
    def get_is_available(self, obj):
        """Check if playlist item is available."""
        return obj.is_available()
    
    def validate(self, data):
        """Validate playlist item data."""
        start_date = data.get('start_date')
        end_date = data.get('end_date')
        
        if start_date and end_date and start_date > end_date:
            raise serializers.ValidationError(
                "Start date cannot be after end date"
            )
        
        return data


class JinglePlaylistSerializer(serializers.ModelSerializer):
    """Basic serializer for JinglePlaylist model."""
    
    channel = ChannelBasicSerializer(read_only=True)
    channel_id = serializers.PrimaryKeyRelatedField(
        queryset=Channel.objects.filter(is_active=True),
        source='channel',
        write_only=True
    )
    created_by = UserBasicSerializer(read_only=True)
    
    # Display fields
    playlist_type_display = serializers.CharField(
        source='get_playlist_type_display',
        read_only=True
    )
    jingle_count = serializers.SerializerMethodField()
    total_duration = serializers.SerializerMethodField()
    total_duration_display = serializers.SerializerMethodField()
    
    class Meta:
        model = JinglePlaylist
        fields = [
            'id', 'name', 'description', 'channel', 'channel_id',
            'playlist_type', 'playlist_type_display', 'is_active',
            'start_time', 'end_time', 'days_of_week', 'auto_rules',
            'created_by', 'jingle_count', 'total_duration',
            'total_duration_display', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'created_by', 'playlist_type_display',
            'jingle_count', 'total_duration', 'total_duration_display',
            'created_at', 'updated_at'
        ]
    
    def get_jingle_count(self, obj):
        """Get number of jingles in playlist."""
        return obj.get_jingle_count()
    
    def get_total_duration(self, obj):
        """Get total duration in seconds."""
        return obj.get_total_duration()
    
    def get_total_duration_display(self, obj):
        """Get human-readable total duration."""
        total_seconds = obj.get_total_duration()
        if total_seconds:
            minutes, seconds = divmod(total_seconds, 60)
            hours, minutes = divmod(minutes, 60)
            if hours:
                return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
            else:
                return f"{minutes:02d}:{seconds:02d}"
        return '00:00'
    
    def validate_days_of_week(self, value):
        """Validate days of week format."""
        if value:
            try:
                days = [int(d.strip()) for d in value.split(',') if d.strip()]
                for day in days:
                    if day < 1 or day > 7:
                        raise ValueError()
            except ValueError:
                raise serializers.ValidationError(
                    "Days of week must be comma-separated numbers from 1-7 (1=Monday)"
                )
        return value
    
    def validate(self, data):
        """Validate playlist data."""
        start_time = data.get('start_time')
        end_time = data.get('end_time')
        
        # For scheduled playlists, time range is required
        if data.get('playlist_type') == 'scheduled':
            if not start_time or not end_time:
                raise serializers.ValidationError(
                    "Start time and end time are required for scheduled playlists"
                )
        
        return data


class JinglePlaylistDetailSerializer(JinglePlaylistSerializer):
    """Detailed serializer for JinglePlaylist model."""
    
    playlist_items = JinglePlaylistItemSerializer(many=True, read_only=True)
    
    class Meta(JinglePlaylistSerializer.Meta):
        fields = JinglePlaylistSerializer.Meta.fields + ['playlist_items']


class JingleScheduleSerializer(serializers.ModelSerializer):
    """Serializer for JingleSchedule model."""
    
    channel = ChannelBasicSerializer(read_only=True)
    channel_id = serializers.PrimaryKeyRelatedField(
        queryset=Channel.objects.filter(is_active=True),
        source='channel',
        write_only=True
    )
    playlist = JinglePlaylistSerializer(read_only=True)
    playlist_id = serializers.PrimaryKeyRelatedField(
        queryset=JinglePlaylist.objects.filter(is_active=True),
        source='playlist',
        write_only=True
    )
    created_by = UserBasicSerializer(read_only=True)
    
    # Display fields
    schedule_type_display = serializers.CharField(
        source='get_schedule_type_display',
        read_only=True
    )
    is_active_now = serializers.SerializerMethodField()
    next_execution = serializers.SerializerMethodField()
    time_range_display = serializers.SerializerMethodField()
    
    class Meta:
        model = JingleSchedule
        fields = [
            'id', 'name', 'channel', 'channel_id', 'schedule_type',
            'schedule_type_display', 'playlist', 'playlist_id',
            'start_time', 'end_time', 'interval_minutes',
            'start_date', 'end_date', 'days_of_week',
            'is_active', 'priority', 'conditions', 'created_by',
            'is_active_now', 'next_execution', 'time_range_display',
            'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'created_by', 'schedule_type_display',
            'is_active_now', 'next_execution', 'time_range_display',
            'created_at', 'updated_at'
        ]
    
    def get_is_active_now(self, obj):
        """Check if schedule is currently active."""
        return obj.is_active_now()
    
    def get_next_execution(self, obj):
        """Get next execution time."""
        next_time = obj.get_next_execution_time()
        return next_time.isoformat() if next_time else None
    
    def get_time_range_display(self, obj):
        """Get human-readable time range."""
        if obj.start_time and obj.end_time:
            return f"{obj.start_time.strftime('%H:%M')} - {obj.end_time.strftime('%H:%M')}"
        elif obj.interval_minutes:
            return f"Every {obj.interval_minutes} minutes"
        return None
    
    def validate_days_of_week(self, value):
        """Validate days of week format."""
        if value:
            try:
                days = [int(d.strip()) for d in value.split(',') if d.strip()]
                for day in days:
                    if day < 1 or day > 7:
                        raise ValueError()
            except ValueError:
                raise serializers.ValidationError(
                    "Days of week must be comma-separated numbers from 1-7 (1=Monday)"
                )
        return value
    
    def validate(self, data):
        """Validate schedule data."""
        schedule_type = data.get('schedule_type')
        start_time = data.get('start_time')
        end_time = data.get('end_time')
        interval_minutes = data.get('interval_minutes')
        start_date = data.get('start_date')
        end_date = data.get('end_date')
        
        # Validate based on schedule type
        if schedule_type == 'interval':
            if not interval_minutes:
                raise serializers.ValidationError(
                    "Interval minutes is required for interval-based schedules"
                )
            if interval_minutes < 1:
                raise serializers.ValidationError(
                    "Interval must be at least 1 minute"
                )
        
        elif schedule_type in ['hourly', 'daily']:
            if not start_time or not end_time:
                raise serializers.ValidationError(
                    f"Start time and end time are required for {schedule_type} schedules"
                )
        
        # Validate date range
        if start_date and end_date and start_date > end_date:
            raise serializers.ValidationError(
                "Start date cannot be after end date"
            )
        
        # Validate playlist belongs to same channel
        playlist = data.get('playlist')
        channel = data.get('channel')
        if playlist and channel and playlist.channel != channel:
            raise serializers.ValidationError(
                "Playlist must belong to the same channel as the schedule"
            )
        
        return data


# Bulk operation serializers
class BulkJingleActionSerializer(serializers.Serializer):
    """Serializer for bulk jingle actions."""
    
    jingle_ids = serializers.ListField(
        child=serializers.IntegerField(),
        min_length=1,
        help_text="List of jingle IDs to perform action on"
    )
    action = serializers.ChoiceField(
        choices=[
            ('approve', 'Approve'),
            ('reject', 'Reject'),
            ('archive', 'Archive'),
            ('activate', 'Activate'),
            ('deactivate', 'Deactivate'),
            ('delete', 'Delete'),
        ],
        help_text="Action to perform on selected jingles"
    )
    
    def validate_jingle_ids(self, value):
        """Validate that all jingle IDs exist."""
        existing_ids = set(
            Jingle.objects.filter(
                id__in=value,
                is_deleted=False
            ).values_list('id', flat=True)
        )
        
        invalid_ids = set(value) - existing_ids
        if invalid_ids:
            raise serializers.ValidationError(
                f"Invalid jingle IDs: {list(invalid_ids)}"
            )
        
        return value


class PlaylistReorderSerializer(serializers.Serializer):
    """Serializer for reordering playlist items."""
    
    item_orders = serializers.ListField(
        child=serializers.DictField(
            child=serializers.IntegerField()
        ),
        min_length=1,
        help_text="List of {id: item_id, order: new_order} objects"
    )
    
    def validate_item_orders(self, value):
        """Validate item order data."""
        for item_data in value:
            if 'id' not in item_data or 'order' not in item_data:
                raise serializers.ValidationError(
                    "Each item must have 'id' and 'order' fields"
                )
            
            if item_data['order'] < 0:
                raise serializers.ValidationError(
                    "Order must be a non-negative integer"
                )
        
        return value