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

from django.db.models import Count, F, Prefetch, Q

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


class RideQuerySet(StatusQuerySet, ReviewableQuerySet):
    """Optimized QuerySet for Ride model."""

    def by_category(self, *, category: str | list[str]):
        """Filter rides by category."""
        if isinstance(category, list):
            return self.filter(category__in=category)
        return self.filter(category=category)

    def coasters(self):
        """Filter for roller coasters."""
        return self.filter(category__in=["RC", "WC"])

    def thrill_rides(self):
        """Filter for thrill rides."""
        return self.filter(category__in=["RC", "WC", "FR"])

    def family_friendly(self, *, max_height_requirement: int = 42):
        """Filter for family-friendly rides."""
        return self.filter(Q(min_height_in__lte=max_height_requirement) | Q(min_height_in__isnull=True))

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

    def by_manufacturer(self, *, manufacturer_id: int):
        """Filter rides by manufacturer."""
        return self.filter(manufacturer_id=manufacturer_id)

    def by_designer(self, *, designer_id: int):
        """Filter rides by designer."""
        return self.filter(designer_id=designer_id)

    def with_capacity_info(self):
        """Add capacity-related annotations."""
        return self.annotate(
            estimated_daily_capacity=F("capacity_per_hour") * 10,  # Assuming 10 operating hours
            duration_minutes=F("ride_duration_seconds") / 60.0,
        )

    def high_capacity(self, *, min_capacity: int = 1000):
        """Filter for high-capacity rides."""
        return self.filter(capacity_per_hour__gte=min_capacity)

    def optimized_for_list(self):
        """Optimize for ride list display."""
        return self.select_related("park", "park_area", "manufacturer", "designer", "ride_model").with_review_stats()

    def optimized_for_detail(self):
        """Optimize for ride detail display."""
        from .models import RideReview

        return self.select_related(
            "park",
            "park__location",
            "park_area",
            "manufacturer",
            "designer",
            "ride_model",
            "ride_model__manufacturer",
        ).prefetch_related(
            "coaster_stats",
            Prefetch(
                "reviews",
                queryset=RideReview.objects.select_related("user")
                .filter(is_published=True)
                .order_by("-created_at")[:10],
            ),
            "photos",
        )

    def with_coaster_stats(self):
        """Always prefetch coaster_stats for roller coaster queries."""
        return self.select_related("park", "manufacturer", "ride_model").prefetch_related("coaster_stats")

    def for_map_display(self):
        """Optimize for map display."""
        return (
            self.select_related("park", "park_area")
            .prefetch_related("location")
            .values(
                "id",
                "name",
                "slug",
                "category",
                "status",
                "park__name",
                "park__slug",
                "park_area__name",
                "location__point",
            )
        )

    def search_by_specs(
        self,
        *,
        min_height: int | None = None,
        max_height: int | None = None,
        min_speed: float | None = None,
        inversions: bool | None = None,
    ):
        """Search rides by physical specifications."""
        queryset = self

        if min_height:
            queryset = queryset.filter(
                Q(rollercoaster_stats__height_ft__gte=min_height) | Q(min_height_in__gte=min_height)
            )

        if max_height:
            queryset = queryset.filter(
                Q(rollercoaster_stats__height_ft__lte=max_height) | Q(max_height_in__lte=max_height)
            )

        if min_speed:
            queryset = queryset.filter(rollercoaster_stats__speed_mph__gte=min_speed)

        if inversions is not None:
            if inversions:
                queryset = queryset.filter(rollercoaster_stats__inversions__gt=0)
            else:
                queryset = queryset.filter(Q(rollercoaster_stats__inversions=0) | Q(rollercoaster_stats__isnull=True))

        return queryset


class RideManager(StatusManager, ReviewableManager):
    """Custom manager for Ride model."""

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

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

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

    def family_friendly(self, *, max_height_requirement: int = 42):
        return self.get_queryset().family_friendly(max_height_requirement=max_height_requirement)

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

    def high_capacity(self, *, min_capacity: int = 1000):
        return self.get_queryset().high_capacity(min_capacity=min_capacity)

    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 with_coaster_stats(self):
        """Always prefetch coaster_stats for roller coaster queries."""
        return self.get_queryset().with_coaster_stats()


class RideModelQuerySet(BaseQuerySet):
    """QuerySet for RideModel model."""

    def by_manufacturer(self, *, manufacturer_id: int):
        """Filter ride models by manufacturer."""
        return self.filter(manufacturer_id=manufacturer_id)

    def by_category(self, *, category: str):
        """Filter ride models by category."""
        return self.filter(category=category)

    def with_ride_counts(self):
        """Add count of rides using this model."""
        return self.annotate(
            ride_count=Count("rides", distinct=True),
            operating_rides_count=Count("rides", filter=Q(rides__status="OPERATING"), distinct=True),
        )

    def popular_models(self, *, min_installations: int = 5):
        """Filter for popular ride models."""
        return self.with_ride_counts().filter(ride_count__gte=min_installations)

    def optimized_for_list(self):
        """Optimize for model list display."""
        return self.select_related("manufacturer").with_ride_counts()


class RideModelManager(BaseManager):
    """Manager for RideModel model."""

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

    def by_manufacturer(self, *, manufacturer_id: int):
        return self.get_queryset().by_manufacturer(manufacturer_id=manufacturer_id)

    def popular_models(self, *, min_installations: int = 5):
        return self.get_queryset().popular_models(min_installations=min_installations)


class RideReviewQuerySet(ReviewableQuerySet):
    """QuerySet for RideReview model."""

    def for_ride(self, *, ride_id: int):
        """Filter reviews for a specific ride."""
        return self.filter(ride_id=ride_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", "ride", "moderated_by")


class RideReviewManager(BaseManager):
    """Manager for RideReview model."""

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

    def for_ride(self, *, ride_id: int):
        return self.get_queryset().for_ride(ride_id=ride_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)


class RollerCoasterStatsQuerySet(BaseQuerySet):
    """QuerySet for RollerCoasterStats model."""

    def tall_coasters(self, *, min_height_ft: float = 200):
        """Filter for tall roller coasters."""
        return self.filter(height_ft__gte=min_height_ft)

    def fast_coasters(self, *, min_speed_mph: float = 60):
        """Filter for fast roller coasters."""
        return self.filter(speed_mph__gte=min_speed_mph)

    def with_inversions(self):
        """Filter for coasters with inversions."""
        return self.filter(inversions__gt=0)

    def launched_coasters(self):
        """Filter for launched coasters."""
        return self.exclude(propulsion_system="NONE")

    def by_track_type(self, *, track_type: str):
        """Filter by track type."""
        return self.filter(track_type=track_type)

    def optimized_for_list(self):
        """Optimize for stats list display."""
        return self.select_related("ride", "ride__park")


class RollerCoasterStatsManager(BaseManager):
    """Manager for RollerCoasterStats model."""

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

    def tall_coasters(self, *, min_height_ft: float = 200):
        return self.get_queryset().tall_coasters(min_height_ft=min_height_ft)

    def fast_coasters(self, *, min_speed_mph: float = 60):
        return self.get_queryset().fast_coasters(min_speed_mph=min_speed_mph)

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

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