"""
Selectors for user and account-related data retrieval.
Following Django styleguide pattern for separating data access from business logic.
"""

from datetime import timedelta
from typing import Any

from django.contrib.auth import get_user_model
from django.db.models import Count, F, Q, QuerySet
from django.utils import timezone

User = get_user_model()


def user_profile_optimized(*, user_id: int) -> Any:
    """
    Get a user with optimized queries for profile display.

    Args:
        user_id: User ID

    Returns:
        User instance with prefetched related data

    Raises:
        User.DoesNotExist: If user doesn't exist
    """
    return (
        User.objects.prefetch_related("park_reviews", "ride_reviews", "socialaccount_set")
        .annotate(
            park_review_count=Count("park_reviews", filter=Q(park_reviews__is_published=True)),
            ride_review_count=Count("ride_reviews", filter=Q(ride_reviews__is_published=True)),
            total_review_count=F("park_review_count") + F("ride_review_count"),
        )
        .get(id=user_id)
    )


def active_users_with_stats() -> QuerySet:
    """
    Get active users with review statistics.

    Returns:
        QuerySet of active users with review counts
    """
    return (
        User.objects.filter(is_active=True)
        .annotate(
            park_review_count=Count("park_reviews", filter=Q(park_reviews__is_published=True)),
            ride_review_count=Count("ride_reviews", filter=Q(ride_reviews__is_published=True)),
            total_review_count=F("park_review_count") + F("ride_review_count"),
        )
        .order_by("-total_review_count")
    )


def users_with_recent_activity(*, days: int = 30) -> QuerySet:
    """
    Get users who have been active in the last N days.

    Args:
        days: Number of days to look back for activity

    Returns:
        QuerySet of recently active users
    """
    cutoff_date = timezone.now() - timedelta(days=days)

    return (
        User.objects.filter(
            Q(last_login__gte=cutoff_date)
            | Q(park_reviews__created_at__gte=cutoff_date)
            | Q(ride_reviews__created_at__gte=cutoff_date)
        )
        .annotate(
            recent_park_reviews=Count(
                "park_reviews",
                filter=Q(park_reviews__created_at__gte=cutoff_date),
            ),
            recent_ride_reviews=Count(
                "ride_reviews",
                filter=Q(ride_reviews__created_at__gte=cutoff_date),
            ),
            recent_total_reviews=F("recent_park_reviews") + F("recent_ride_reviews"),
        )
        .order_by("-last_login")
        .distinct()
    )


def top_reviewers(*, limit: int = 10) -> QuerySet:
    """
    Get top users by review count.

    Args:
        limit: Maximum number of users to return

    Returns:
        QuerySet of top reviewers
    """
    return (
        User.objects.filter(is_active=True)
        .annotate(
            park_review_count=Count("park_reviews", filter=Q(park_reviews__is_published=True)),
            ride_review_count=Count("ride_reviews", filter=Q(ride_reviews__is_published=True)),
            total_review_count=F("park_review_count") + F("ride_review_count"),
        )
        .filter(total_review_count__gt=0)
        .order_by("-total_review_count")[:limit]
    )


def moderator_users() -> QuerySet:
    """
    Get users with moderation permissions.

    Returns:
        QuerySet of users who can moderate content
    """
    return (
        User.objects.filter(
            Q(is_staff=True)
            | Q(groups__name="Moderators")
            | Q(
                user_permissions__codename__in=[
                    "change_parkreview",
                    "change_ridereview",
                ]
            )
        )
        .distinct()
        .order_by("username")
    )


def users_by_registration_date(*, start_date, end_date) -> QuerySet:
    """
    Get users who registered within a date range.

    Args:
        start_date: Start of date range
        end_date: End of date range

    Returns:
        QuerySet of users registered in the date range
    """
    return User.objects.filter(date_joined__date__gte=start_date, date_joined__date__lte=end_date).order_by(
        "-date_joined"
    )


def user_search_autocomplete(*, query: str, limit: int = 10) -> QuerySet:
    """
    Get users matching a search query for autocomplete functionality.

    Args:
        query: Search string
        limit: Maximum number of results

    Returns:
        QuerySet of matching users for autocomplete
    """
    return User.objects.filter(
        Q(username__icontains=query) | Q(display_name__icontains=query),
        is_active=True,
    ).order_by("username")[:limit]


def users_with_social_accounts() -> QuerySet:
    """
    Get users who have connected social accounts.

    Returns:
        QuerySet of users with social account connections
    """
    return (
        User.objects.filter(socialaccount__isnull=False)
        .prefetch_related("socialaccount_set")
        .distinct()
        .order_by("username")
    )


def user_statistics_summary() -> dict[str, Any]:
    """
    Get overall user statistics for dashboard/analytics.

    Returns:
        Dictionary containing user statistics
    """
    total_users = User.objects.count()
    active_users = User.objects.filter(is_active=True).count()
    staff_users = User.objects.filter(is_staff=True).count()

    # Users with reviews
    users_with_reviews = (
        User.objects.filter(Q(park_reviews__isnull=False) | Q(ride_reviews__isnull=False)).distinct().count()
    )

    # Recent registrations (last 30 days)
    cutoff_date = timezone.now() - timedelta(days=30)
    recent_registrations = User.objects.filter(date_joined__gte=cutoff_date).count()

    return {
        "total_users": total_users,
        "active_users": active_users,
        "inactive_users": total_users - active_users,
        "staff_users": staff_users,
        "users_with_reviews": users_with_reviews,
        "recent_registrations": recent_registrations,
        "review_participation_rate": ((users_with_reviews / total_users * 100) if total_users > 0 else 0),
    }


def users_needing_email_verification() -> QuerySet:
    """
    Get users who haven't verified their email addresses.

    Returns:
        QuerySet of users with unverified emails
    """
    return User.objects.filter(is_active=True, emailaddress__verified=False).distinct().order_by("date_joined")


def users_by_review_activity(*, min_reviews: int = 1) -> QuerySet:
    """
    Get users who have written at least a minimum number of reviews.

    Args:
        min_reviews: Minimum number of reviews required

    Returns:
        QuerySet of users with sufficient review activity
    """
    return (
        User.objects.annotate(
            park_review_count=Count("park_reviews", filter=Q(park_reviews__is_published=True)),
            ride_review_count=Count("ride_reviews", filter=Q(ride_reviews__is_published=True)),
            total_review_count=F("park_review_count") + F("ride_review_count"),
        )
        .filter(total_review_count__gte=min_reviews)
        .order_by("-total_review_count")
    )
