"""
Leaderboard views for user rankings
"""

from datetime import timedelta

from django.db.models import Count, Sum
from django.db.models.functions import Coalesce
from django.utils import timezone
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response

from apps.moderation.models import EditSubmission
from apps.reviews.models import Review
from apps.rides.models import RideCredit


@api_view(["GET"])
@permission_classes([AllowAny])
def leaderboard(request):
    """
    Get user leaderboard data.

    Query params:
    - category: 'credits' | 'reviews' | 'contributions' (default: credits)
    - period: 'all' | 'monthly' | 'weekly' (default: all)
    - limit: int (default: 25, max: 100)
    """
    category = request.query_params.get("category", "credits")
    period = request.query_params.get("period", "all")
    limit = min(int(request.query_params.get("limit", 25)), 100)

    # Calculate date filter based on period
    date_filter = None
    if period == "weekly":
        date_filter = timezone.now() - timedelta(days=7)
    elif period == "monthly":
        date_filter = timezone.now() - timedelta(days=30)

    if category == "credits":
        return _get_credits_leaderboard(date_filter, limit)
    elif category == "reviews":
        return _get_reviews_leaderboard(date_filter, limit)
    elif category == "contributions":
        return _get_contributions_leaderboard(date_filter, limit)
    else:
        return Response({"detail": "Invalid category"}, status=400)


def _get_credits_leaderboard(date_filter, limit):
    """Top users by total ride credits."""
    queryset = RideCredit.objects.all()

    if date_filter:
        queryset = queryset.filter(created_at__gte=date_filter)

    # Aggregate credits per user
    users_data = (
        queryset.values("user_id", "user__username", "user__display_name")
        .annotate(
            total_credits=Coalesce(Sum("count"), 0),
            unique_rides=Count("ride", distinct=True),
        )
        .order_by("-total_credits")[:limit]
    )

    results = []
    for rank, entry in enumerate(users_data, 1):
        results.append(
            {
                "rank": rank,
                "user_id": entry["user_id"],
                "username": entry["user__username"],
                "display_name": entry["user__display_name"] or entry["user__username"],
                "total_credits": entry["total_credits"],
                "unique_rides": entry["unique_rides"],
            }
        )

    return Response(
        {
            "category": "credits",
            "results": results,
        }
    )


def _get_reviews_leaderboard(date_filter, limit):
    """Top users by review count."""
    queryset = Review.objects.all()

    if date_filter:
        queryset = queryset.filter(created_at__gte=date_filter)

    # Count reviews per user
    users_data = (
        queryset.values("user_id", "user__username", "user__display_name")
        .annotate(
            review_count=Count("id"),
        )
        .order_by("-review_count")[:limit]
    )

    results = []
    for rank, entry in enumerate(users_data, 1):
        results.append(
            {
                "rank": rank,
                "user_id": entry["user_id"],
                "username": entry["user__username"],
                "display_name": entry["user__display_name"] or entry["user__username"],
                "review_count": entry["review_count"],
            }
        )

    return Response(
        {
            "category": "reviews",
            "results": results,
        }
    )


def _get_contributions_leaderboard(date_filter, limit):
    """Top users by approved contributions."""
    queryset = EditSubmission.objects.filter(status="approved")

    if date_filter:
        queryset = queryset.filter(created_at__gte=date_filter)

    # Count contributions per user
    users_data = (
        queryset.values("submitted_by_id", "submitted_by__username", "submitted_by__display_name")
        .annotate(
            contribution_count=Count("id"),
        )
        .order_by("-contribution_count")[:limit]
    )

    results = []
    for rank, entry in enumerate(users_data, 1):
        results.append(
            {
                "rank": rank,
                "user_id": entry["submitted_by_id"],
                "username": entry["submitted_by__username"],
                "display_name": entry["submitted_by__display_name"] or entry["submitted_by__username"],
                "contribution_count": entry["contribution_count"],
            }
        )

    return Response(
        {
            "category": "contributions",
            "results": results,
        }
    )
