from rest_framework import serializers
from django.db.models import Count, Avg, Sum, Q
from django.db.models.functions import TruncDay, TruncHour


class DownloaderRecordSerializer(serializers.Serializer):
    """Single download history entry."""
    id = serializers.IntegerField()
    url = serializers.URLField()
    title = serializers.CharField()
    platform = serializers.CharField()
    format = serializers.CharField()
    video_quality = serializers.IntegerField(allow_null=True)
    is_audio_only = serializers.BooleanField()
    length_of_media = serializers.IntegerField(allow_null=True)
    file_size = serializers.IntegerField(allow_null=True)
    processing_time = serializers.FloatField(allow_null=True)
    success = serializers.BooleanField()
    error_message = serializers.CharField()
    download_time = serializers.DateTimeField()


class PlatformCountSerializer(serializers.Serializer):
    platform = serializers.CharField()
    count = serializers.IntegerField()


class QualityCountSerializer(serializers.Serializer):
    video_quality = serializers.IntegerField(allow_null=True)
    count = serializers.IntegerField()


class TimeseriesPointSerializer(serializers.Serializer):
    period = serializers.DateTimeField()
    count = serializers.IntegerField()


class TopUrlSerializer(serializers.Serializer):
    url = serializers.URLField()
    title = serializers.CharField()
    count = serializers.IntegerField()


class DownloaderStatsSerializer(serializers.Serializer):
    # Totals
    total_downloads = serializers.IntegerField()
    successful_downloads = serializers.IntegerField()
    failed_downloads = serializers.IntegerField()
    success_rate = serializers.FloatField(help_text="Percentage 0-100")

    # Media metrics
    avg_length_of_media = serializers.FloatField(allow_null=True)
    total_length_of_media = serializers.IntegerField(allow_null=True)
    avg_file_size = serializers.FloatField(allow_null=True)
    total_file_size = serializers.IntegerField(allow_null=True)
    avg_processing_time = serializers.FloatField(allow_null=True)

    # Format / quality breakdown
    most_common_format = serializers.CharField(allow_null=True)
    audio_only_count = serializers.IntegerField()
    video_count = serializers.IntegerField()
    downloads_by_platform = PlatformCountSerializer(many=True)
    downloads_by_quality = QualityCountSerializer(many=True)

    # Top content
    most_downloaded_urls = TopUrlSerializer(many=True)

    # Timeseries
    downloads_per_day = TimeseriesPointSerializer(many=True)
    downloads_per_hour = TimeseriesPointSerializer(many=True)

    def to_representation(self, qs):
        agg = qs.aggregate(
            total_downloads=Count('id'),
            successful_downloads=Count('id', filter=Q(success=True)),
            failed_downloads=Count('id', filter=Q(success=False)),
            avg_length_of_media=Avg('length_of_media'),
            total_length_of_media=Sum('length_of_media'),
            avg_file_size=Avg('file_size'),
            total_file_size=Sum('file_size'),
            avg_processing_time=Avg('processing_time'),
            audio_only_count=Count('id', filter=Q(is_audio_only=True)),
            video_count=Count('id', filter=Q(is_audio_only=False)),
        )

        total = agg['total_downloads'] or 0
        agg['success_rate'] = round(agg['successful_downloads'] / total * 100, 2) if total else 0.0

        most_common = qs.values('format').annotate(count=Count('id')).order_by('-count').first()
        agg['most_common_format'] = most_common['format'] if most_common else None

        agg['downloads_by_platform'] = list(
            qs.values('platform').annotate(count=Count('id')).order_by('-count')
        )
        agg['downloads_by_quality'] = list(
            qs.values('video_quality').annotate(count=Count('id')).order_by('-count')
        )
        agg['most_downloaded_urls'] = list(
            qs.values('url', 'title').annotate(count=Count('id')).order_by('-count')[:10]
        )
        agg['downloads_per_day'] = list(
            qs.annotate(period=TruncDay('download_time'))
            .values('period').annotate(count=Count('id')).order_by('period')
        )
        agg['downloads_per_hour'] = list(
            qs.annotate(period=TruncHour('download_time'))
            .values('period').annotate(count=Count('id')).order_by('period')
        )

        return super().to_representation(agg)
