"""
Custom managers and QuerySets for Parks models.
Optimized queries following Django styleguide patterns.
"""

from django.db.models import Avg, Count, Max, Min, Prefetch, Q

from apps.core.managers import (
    BaseManager,
    BaseQuerySet,
    LocationManager,
    LocationQuerySet,
    ReviewableManager,
    ReviewableQuerySet,
    StatusManager,
    StatusQuerySet,
)


class ParkQuerySet(StatusQuerySet, ReviewableQuerySet, LocationQuerySet):
    """Optimized QuerySet for Park model."""

    def with_complete_stats(self):
        """Add comprehensive park statistics."""
        return self.annotate(
            ride_count_calculated=Count("rides", distinct=True),
            coaster_count_calculated=Count(
                "rides",
                filter=Q(rides__category__in=["RC", "WC"]),
                distinct=True,
            ),
            area_count=Count("areas", distinct=True),
            review_count=Count("reviews", filter=Q(reviews__is_published=True), distinct=True),
            average_rating_calculated=Avg("reviews__rating", filter=Q(reviews__is_published=True)),
            latest_ride_opening=Max("rides__opening_date"),
            oldest_ride_opening=Min("rides__opening_date"),
        )

    def optimized_for_list(self):
        """Optimize for park list display."""
        return self.select_related("operator", "property_owner").prefetch_related("location").with_complete_stats()

    def optimized_for_detail(self):
        """Optimize for park detail display."""
        from apps.rides.models import Ride

        from .models import ParkReview

        return self.select_related("operator", "property_owner").prefetch_related(
            "location",
            "areas",
            Prefetch(
                "rides",
                queryset=Ride.objects.select_related("manufacturer", "designer", "ride_model", "park_area").order_by(
                    "name"
                ),
            ),
            Prefetch(
                "reviews",
                queryset=ParkReview.objects.select_related("user")
                .filter(is_published=True)
                .order_by("-created_at")[:10],
            ),
            "photos",
        )

    def by_operator(self, *, operator_id: int):
        """Filter parks by operator."""
        return self.filter(operator_id=operator_id)

    def by_property_owner(self, *, owner_id: int):
        """Filter parks by property owner."""
        return self.filter(property_owner_id=owner_id)

    def with_minimum_coasters(self, *, min_coasters: int = 5):
        """Filter parks with minimum number of coasters."""
        return self.with_complete_stats().filter(coaster_count_calculated__gte=min_coasters)

    def large_parks(self, *, min_acres: float = 100.0):
        """Filter for large parks."""
        return self.filter(size_acres__gte=min_acres)

    def seasonal_parks(self):
        """Filter for parks with seasonal operation."""
        return self.exclude(operating_season__exact="")

    def for_map_display(self, *, bounds=None):
        """Optimize for map display with minimal data."""
        queryset = self.select_related("operator").prefetch_related("location")

        if bounds:
            queryset = queryset.within_bounds(
                north=bounds.north,
                south=bounds.south,
                east=bounds.east,
                west=bounds.west,
            )

        return queryset.values(
            "id",
            "name",
            "slug",
            "status",
            "location__latitude",
            "location__longitude",
            "location__city",
            "location__state",
            "location__country",
            "operator__name",
        )

    def search_autocomplete(self, *, query: str, limit: int = 10):
        """Optimized search for autocomplete."""
        return (
            self.filter(
                Q(name__icontains=query) | Q(location__city__icontains=query) | Q(location__state__icontains=query)
            )
            .select_related("operator", "location")
            .only("id", "name", "slug", "location__city", "location__state", "operator__name")[:limit]
        )

    def with_location(self):
        """Always prefetch location for park queries."""
        return self.select_related("operator").prefetch_related("location")


class ParkManager(StatusManager, ReviewableManager, LocationManager):
    """Custom manager for Park model."""

    def get_queryset(self):
        return ParkQuerySet(self.model, using=self._db)

    def with_complete_stats(self):
        return self.get_queryset().with_complete_stats()

    def optimized_for_list(self):
        return self.get_queryset().optimized_for_list()

    def optimized_for_detail(self):
        return self.get_queryset().optimized_for_detail()

    def by_operator(self, *, operator_id: int):
        return self.get_queryset().by_operator(operator_id=operator_id)

    def large_parks(self, *, min_acres: float = 100.0):
        return self.get_queryset().large_parks(min_acres=min_acres)

    def for_map_display(self, *, bounds=None):
        return self.get_queryset().for_map_display(bounds=bounds)

    def with_location(self):
        """Always prefetch location for park queries."""
        return self.get_queryset().with_location()


class ParkAreaQuerySet(BaseQuerySet):
    """QuerySet for ParkArea model."""

    def with_ride_counts(self):
        """Add ride count annotations."""
        return self.annotate(
            ride_count=Count("rides", distinct=True),
            coaster_count=Count(
                "rides",
                filter=Q(rides__category__in=["RC", "WC"]),
                distinct=True,
            ),
        )

    def optimized_for_list(self):
        """Optimize for area list display."""
        return self.select_related("park").with_ride_counts()

    def by_park(self, *, park_id: int):
        """Filter areas by park."""
        return self.filter(park_id=park_id)

    def with_rides(self):
        """Filter areas that have rides."""
        return self.filter(rides__isnull=False).distinct()


class ParkAreaManager(BaseManager):
    """Manager for ParkArea model."""

    def get_queryset(self):
        return ParkAreaQuerySet(self.model, using=self._db)

    def with_ride_counts(self):
        return self.get_queryset().with_ride_counts()

    def by_park(self, *, park_id: int):
        return self.get_queryset().by_park(park_id=park_id)


class ParkReviewQuerySet(ReviewableQuerySet):
    """QuerySet for ParkReview model."""

    def for_park(self, *, park_id: int):
        """Filter reviews for a specific park."""
        return self.filter(park_id=park_id)

    def by_user(self, *, user_id: int):
        """Filter reviews by user."""
        return self.filter(user_id=user_id)

    def by_rating_range(self, *, min_rating: int = 1, max_rating: int = 10):
        """Filter reviews by rating range."""
        return self.filter(rating__gte=min_rating, rating__lte=max_rating)

    def optimized_for_display(self):
        """Optimize for review display."""
        return self.select_related("user", "park", "moderated_by")

    def recent_reviews(self, *, days: int = 30):
        """Get recent reviews."""
        return self.recent(days=days)

    def moderation_required(self):
        """Filter reviews requiring moderation."""
        return self.filter(Q(is_published=False) | Q(moderated_at__isnull=True))


class ParkReviewManager(BaseManager):
    """Manager for ParkReview model."""

    def get_queryset(self):
        return ParkReviewQuerySet(self.model, using=self._db)

    def for_park(self, *, park_id: int):
        return self.get_queryset().for_park(park_id=park_id)

    def by_rating_range(self, *, min_rating: int = 1, max_rating: int = 10):
        return self.get_queryset().by_rating_range(min_rating=min_rating, max_rating=max_rating)

    def moderation_required(self):
        return self.get_queryset().moderation_required()


class CompanyQuerySet(BaseQuerySet):
    """QuerySet for Company model."""

    def operators(self):
        """Filter for companies that operate parks."""
        return self.filter(roles__contains=["OPERATOR"])

    def property_owners(self):
        """Filter for companies that own park properties."""
        return self.filter(roles__contains=["PROPERTY_OWNER"])

    def manufacturers(self):
        """Filter for ride manufacturers."""
        return self.filter(roles__contains=["MANUFACTURER"])

    def with_park_counts(self):
        """Add park count annotations."""
        return self.annotate(
            operated_parks_count=Count("operated_parks", distinct=True),
            owned_parks_count=Count("owned_parks", distinct=True),
            total_parks_involvement=Count("operated_parks", distinct=True) + Count("owned_parks", distinct=True),
        )

    def major_operators(self, *, min_parks: int = 5):
        """Filter for major park operators."""
        return self.operators().with_park_counts().filter(operated_parks_count__gte=min_parks)

    def optimized_for_list(self):
        """Optimize for company list display."""
        return self.with_park_counts()


class CompanyManager(BaseManager):
    """Manager for Company model."""

    def get_queryset(self):
        return CompanyQuerySet(self.model, using=self._db)

    def operators(self):
        return self.get_queryset().operators()

    def manufacturers(self):
        return self.get_queryset().manufacturers()

    def major_operators(self, *, min_parks: int = 5):
        return self.get_queryset().major_operators(min_parks=min_parks)

    def manufacturers_with_ride_count(self):
        """Get manufacturers with ride count annotation for list views."""
        return (
            self.get_queryset()
            .manufacturers()
            .annotate(ride_count=Count("manufactured_rides", distinct=True))
            .only("id", "name", "slug", "roles", "description")
            .order_by("name")
        )

    def designers_with_ride_count(self):
        """Get designers with ride count annotation for list views."""
        return (
            self.get_queryset()
            .filter(roles__contains=["DESIGNER"])
            .annotate(ride_count=Count("designed_rides", distinct=True))
            .only("id", "name", "slug", "roles", "description")
            .order_by("name")
        )

    def operators_with_park_count(self):
        """Get operators with park count annotation for list views."""
        return (
            self.get_queryset()
            .operators()
            .with_park_counts()
            .only("id", "name", "slug", "roles", "description")
            .order_by("name")
        )
