"""
Full-featured Parks API views for ThrillWiki API v1.

This module implements comprehensive park endpoints with full filtering support:
- List / Create: GET /parks/  POST /parks/
- Retrieve / Update / Delete: GET /parks/{pk}/  PATCH/PUT/DELETE
- Filter options: GET /parks/filter-options/
- Company search: GET /parks/search/companies/?q=...
- Search suggestions: GET /parks/search-suggestions/?q=...

Supports all 24 filtering parameters from frontend API documentation.
"""

import contextlib
from typing import Any

from django.db import models
from django.db.models import Avg, Count, Q
from django.db.models.query import QuerySet
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework import permissions, status
from rest_framework.exceptions import NotFound
from rest_framework.pagination import PageNumberPagination
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

# Import models
try:
    from apps.parks.models import Company, Park

    MODELS_AVAILABLE = True
except Exception:
    Park = None  # type: ignore
    Company = None  # type: ignore
    MODELS_AVAILABLE = False

# Import ModelChoices for filter options
try:
    from apps.api.v1.serializers.shared import ModelChoices

    HAVE_MODELCHOICES = True
except Exception:
    ModelChoices = None  # type: ignore
    HAVE_MODELCHOICES = False

# Import serializers
try:
    from apps.api.v1.serializers.parks import (
        ParkCreateInputSerializer,
        ParkDetailOutputSerializer,
        ParkImageSettingsInputSerializer,
        ParkListOutputSerializer,
        ParkUpdateInputSerializer,
    )

    SERIALIZERS_AVAILABLE = True
except Exception:
    SERIALIZERS_AVAILABLE = False


class StandardResultsSetPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = "page_size"
    max_page_size = 1000


# --- Park list & create -----------------------------------------------------
class ParkListCreateAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    @extend_schema(
        summary="List parks with comprehensive filtering and pagination",
        description="List parks with comprehensive filtering matching frontend API documentation. Supports all 24 filtering parameters including continent, rating ranges, ride counts, and more.",
        parameters=[
            # Pagination
            OpenApiParameter(
                name="page", location=OpenApiParameter.QUERY, type=OpenApiTypes.INT, description="Page number"
            ),
            OpenApiParameter(
                name="page_size",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Number of results per page",
            ),
            # Search
            OpenApiParameter(
                name="search",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Search parks by name",
            ),
            # Location filters
            OpenApiParameter(
                name="continent",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Filter by continent",
            ),
            OpenApiParameter(
                name="country", location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, description="Filter by country"
            ),
            OpenApiParameter(
                name="state",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Filter by state/province",
            ),
            OpenApiParameter(
                name="city", location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, description="Filter by city"
            ),
            # Park attributes
            OpenApiParameter(
                name="park_type",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Filter by park type",
            ),
            OpenApiParameter(
                name="status",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Filter by operational status",
            ),
            # Company filters
            OpenApiParameter(
                name="operator_id",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Filter by operator company ID",
            ),
            OpenApiParameter(
                name="operator_slug",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Filter by operator company slug",
            ),
            OpenApiParameter(
                name="property_owner_id",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Filter by property owner company ID",
            ),
            OpenApiParameter(
                name="property_owner_slug",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Filter by property owner company slug",
            ),
            # Rating filters
            OpenApiParameter(
                name="min_rating",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.NUMBER,
                description="Minimum average rating",
            ),
            OpenApiParameter(
                name="max_rating",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.NUMBER,
                description="Maximum average rating",
            ),
            # Ride count filters
            OpenApiParameter(
                name="min_ride_count",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Minimum total ride count",
            ),
            OpenApiParameter(
                name="max_ride_count",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Maximum total ride count",
            ),
            # Opening year filters
            OpenApiParameter(
                name="opening_year",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Filter by specific opening year",
            ),
            OpenApiParameter(
                name="min_opening_year",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Minimum opening year",
            ),
            OpenApiParameter(
                name="max_opening_year",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Maximum opening year",
            ),
            # Roller coaster filters
            OpenApiParameter(
                name="has_roller_coasters",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.BOOL,
                description="Filter parks that have roller coasters",
            ),
            OpenApiParameter(
                name="min_roller_coaster_count",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Minimum roller coaster count",
            ),
            OpenApiParameter(
                name="max_roller_coaster_count",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Maximum roller coaster count",
            ),
            # Ordering
            OpenApiParameter(
                name="ordering",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="Order results by field (prefix with - for descending)",
            ),
        ],
        responses={200: ("ParkListOutputSerializer(many=True)" if SERIALIZERS_AVAILABLE else OpenApiTypes.OBJECT)},
        tags=["Parks"],
    )
    def get(self, request: Request) -> Response:
        """List parks with comprehensive filtering and pagination."""
        if not MODELS_AVAILABLE:
            return Response(
                {
                    "detail": (
                        "Park listing is not available because domain models "
                        "are not imported. Implement apps.parks.models.Park "
                        "(and related managers) to enable listing."
                    )
                },
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )

        # Start with base queryset
        qs = (
            Park.objects.all()
            .select_related("operator", "property_owner", "location")
            .prefetch_related("rides")
            .annotate(
                ride_count_calculated=Count("rides"),
                roller_coaster_count_calculated=Count("rides", filter=Q(rides__category="RC")),
                average_rating_calculated=Avg("reviews__rating"),
            )
        )

        # Apply comprehensive filtering
        qs = self._apply_filters(qs, request.query_params)

        # Apply ordering
        ordering = request.query_params.get("ordering", "name")
        if ordering:
            qs = qs.order_by(ordering)

        # Paginate results
        paginator = StandardResultsSetPagination()
        page = paginator.paginate_queryset(qs, request)

        if SERIALIZERS_AVAILABLE:
            serializer = ParkListOutputSerializer(page, many=True, context={"request": request})
            return paginator.get_paginated_response(serializer.data)
        else:
            # Fallback serialization
            serializer_data = [
                {
                    "id": park.id,
                    "name": park.name,
                    "slug": getattr(park, "slug", ""),
                    "description": getattr(park, "description", ""),
                    "location": {
                        "country": getattr(park.location, "country", "") if hasattr(park, "location") else "",
                        "state": getattr(park.location, "state", "") if hasattr(park, "location") else "",
                        "city": getattr(park.location, "city", "") if hasattr(park, "location") else "",
                    },
                    "operator": {
                        "id": park.operator.id if park.operator else None,
                        "name": park.operator.name if park.operator else "",
                        "slug": getattr(park.operator, "slug", "") if park.operator else "",
                    },
                    "ride_count": getattr(park, "ride_count", 0),
                    "roller_coaster_count": getattr(park, "roller_coaster_count", 0),
                    "average_rating": getattr(park, "average_rating", None),
                }
                for park in page
            ]
            return paginator.get_paginated_response(serializer_data)

    def _apply_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply filtering to the queryset based on actual model fields."""
        qs = self._apply_search_filters(qs, params)
        qs = self._apply_location_filters(qs, params)
        qs = self._apply_park_attribute_filters(qs, params)
        qs = self._apply_company_filters(qs, params)
        qs = self._apply_rating_filters(qs, params)
        qs = self._apply_ride_count_filters(qs, params)
        qs = self._apply_opening_year_filters(qs, params)
        qs = self._apply_roller_coaster_filters(qs, params)
        return qs

    def _apply_search_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply search filtering to the queryset."""
        search = params.get("search")
        if search:
            qs = qs.filter(
                Q(name__icontains=search)
                | Q(description__icontains=search)
                | Q(location__city__icontains=search)
                | Q(location__state__icontains=search)
                | Q(location__country__icontains=search)
            )
        return qs

    def _apply_location_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply location-based filtering to the queryset."""
        location_filters = {
            "country": "location__country__iexact",
            "state": "location__state__iexact",
            "city": "location__city__iexact",
            "continent": "location__continent__iexact",
        }

        for param_name, filter_field in location_filters.items():
            value = params.get(param_name)
            if value:
                qs = qs.filter(**{filter_field: value})

        return qs

    def _apply_park_attribute_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply park attribute filtering to the queryset."""
        # Slug filter - exact match for single park lookup
        slug = params.get("slug")
        if slug:
            qs = qs.filter(slug=slug)

        park_type = params.get("park_type")
        if park_type:
            qs = qs.filter(park_type=park_type)

        status_filter = params.get("status")
        if status_filter:
            qs = qs.filter(status=status_filter)

        return qs

    def _apply_company_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply company-related filtering to the queryset."""
        company_filters = {
            "operator_id": "operator_id",
            "operator_slug": "operator__slug",
            "property_owner_id": "property_owner_id",
            "property_owner_slug": "property_owner__slug",
        }

        for param_name, filter_field in company_filters.items():
            value = params.get(param_name)
            if value:
                qs = qs.filter(**{filter_field: value})

        return qs

    def _apply_rating_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply rating-based filtering to the queryset."""
        min_rating = params.get("min_rating")
        if min_rating:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(average_rating__gte=float(min_rating))

        max_rating = params.get("max_rating")
        if max_rating:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(average_rating__lte=float(max_rating))

        return qs

    def _apply_ride_count_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply ride count filtering to the queryset."""
        min_ride_count = params.get("min_ride_count")
        if min_ride_count:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(ride_count__gte=int(min_ride_count))

        max_ride_count = params.get("max_ride_count")
        if max_ride_count:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(ride_count__lte=int(max_ride_count))

        return qs

    def _apply_opening_year_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply opening year filtering to the queryset."""
        opening_year = params.get("opening_year")
        if opening_year:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(opening_date__year=int(opening_year))

        min_opening_year = params.get("min_opening_year")
        if min_opening_year:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(opening_date__year__gte=int(min_opening_year))

        max_opening_year = params.get("max_opening_year")
        if max_opening_year:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(opening_date__year__lte=int(max_opening_year))

        return qs

    def _apply_roller_coaster_filters(self, qs: QuerySet, params: dict) -> QuerySet:
        """Apply roller coaster filtering to the queryset."""
        has_roller_coasters = params.get("has_roller_coasters")
        if has_roller_coasters is not None:
            if has_roller_coasters.lower() in ["true", "1", "yes"]:
                qs = qs.filter(coaster_count__gt=0)
            elif has_roller_coasters.lower() in ["false", "0", "no"]:
                qs = qs.filter(coaster_count=0)

        min_roller_coaster_count = params.get("min_roller_coaster_count")
        if min_roller_coaster_count:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(coaster_count__gte=int(min_roller_coaster_count))

        max_roller_coaster_count = params.get("max_roller_coaster_count")
        if max_roller_coaster_count:
            with contextlib.suppress(ValueError, TypeError):
                qs = qs.filter(coaster_count__lte=int(max_roller_coaster_count))

        return qs

    @extend_schema(
        summary="Create a new park",
        description="Create a new park.",
        responses={201: ("ParkDetailOutputSerializer()" if SERIALIZERS_AVAILABLE else OpenApiTypes.OBJECT)},
        tags=["Parks"],
    )
    def post(self, request: Request) -> Response:
        """Create a new park."""
        if not SERIALIZERS_AVAILABLE:
            return Response(
                {
                    "detail": "Park creation serializers not available. "
                    "Implement park serializers to enable creation."
                },
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )

        serializer_in = ParkCreateInputSerializer(data=request.data)
        serializer_in.is_valid(raise_exception=True)

        if not MODELS_AVAILABLE:
            return Response(
                {
                    "detail": (
                        "Park creation is not available because domain models "
                        "are not imported. Implement apps.parks.models.Park "
                        "and necessary create logic."
                    )
                },
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )

        validated = serializer_in.validated_data

        # Minimal create logic using model fields if available.
        park = Park.objects.create(  # type: ignore
            name=validated["name"],
            description=validated.get("description", ""),
            # Add other fields as needed based on Park model
        )

        out_serializer = ParkDetailOutputSerializer(park, context={"request": request})
        return Response(out_serializer.data, status=status.HTTP_201_CREATED)


# --- Park retrieve / update / delete ---------------------------------------
@extend_schema(
    summary="Retrieve, update or delete a park by ID or slug",
    description="Retrieve full park details including location, photos, areas, rides, and company information. Supports both ID and slug-based lookup with historical slug support.",
    responses={
        200: ("ParkDetailOutputSerializer()" if SERIALIZERS_AVAILABLE else OpenApiTypes.OBJECT),
        404: OpenApiTypes.OBJECT,
    },
    tags=["Parks"],
)
class ParkDetailAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def _get_park_or_404(self, identifier: str) -> Any:
        if not MODELS_AVAILABLE:
            raise NotFound(
                "Park detail is not available because domain models "
                "are not imported. Implement apps.parks.models.Park "
                "to enable detail endpoints."
            )

        # Try to parse as integer ID first
        try:
            pk = int(identifier)
            try:
                return (
                    Park.objects.select_related("operator", "property_owner", "location")
                    .prefetch_related("areas", "rides", "photos")
                    .get(pk=pk)
                )
            except Park.DoesNotExist:
                raise NotFound("Park not found") from None
        except ValueError:
            # Not an integer, try slug lookup
            try:
                park, is_historical = Park.get_by_slug(identifier)
                # Ensure we have the full related data
                return (
                    Park.objects.select_related("operator", "property_owner", "location")
                    .prefetch_related("areas", "rides", "photos")
                    .get(pk=park.pk)
                )
            except Park.DoesNotExist:
                raise NotFound("Park not found") from None

    @extend_schema(
        summary="Get park full details",
        description="""
        Retrieve comprehensive park details including:

        **Core Information:**
        - Basic park details (name, slug, description, status)
        - Opening/closing dates and operating season
        - Size in acres and website URL
        - Statistics (average rating, ride count, coaster count)

        **Location Data:**
        - Full address with coordinates
        - City, state, country information
        - Formatted address string

        **Company Information:**
        - Operating company details
        - Property owner information (if different)

        **Media:**
        - All approved photos with Cloudflare variants
        - Primary photo designation
        - Banner and card image settings

        **Related Content:**
        - Park areas/themed sections
        - Associated rides (summary)

        **Lookup Methods:**
        - By ID: `/api/v1/parks/123/`
        - By current slug: `/api/v1/parks/cedar-point/`
        - By historical slug: `/api/v1/parks/old-cedar-point-name/`

        **No Query Parameters Required** - This endpoint returns full details by default.
        """,
        responses={
            200: ("ParkDetailOutputSerializer()" if SERIALIZERS_AVAILABLE else OpenApiTypes.OBJECT),
            404: OpenApiTypes.OBJECT,
        },
    )
    def get(self, request: Request, pk: str) -> Response:
        park = self._get_park_or_404(pk)
        if SERIALIZERS_AVAILABLE:
            serializer = ParkDetailOutputSerializer(park, context={"request": request})
            return Response(serializer.data)
        else:
            # Fallback serialization
            return Response(
                {
                    "id": park.id,
                    "name": park.name,
                    "slug": getattr(park, "slug", ""),
                    "description": getattr(park, "description", ""),
                    "location": str(getattr(park, "location", "")),
                    "operator": (getattr(park.operator, "name", "") if hasattr(park, "operator") else ""),
                }
            )

    def patch(self, request: Request, pk: str) -> Response:
        park = self._get_park_or_404(pk)
        if not SERIALIZERS_AVAILABLE:
            return Response(
                {"detail": "Park update serializers not available."},
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )

        serializer_in = ParkUpdateInputSerializer(data=request.data, partial=True)
        serializer_in.is_valid(raise_exception=True)

        if not MODELS_AVAILABLE:
            return Response(
                {"detail": ("Park update is not available because domain models " "are not imported.")},
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )
        for key, value in serializer_in.validated_data.items():
            setattr(park, key, value)
        park.save()
        serializer = ParkDetailOutputSerializer(park, context={"request": request})
        return Response(serializer.data)

    def put(self, request: Request, pk: str) -> Response:
        # Full replace - reuse patch behavior for simplicity
        return self.patch(request, pk)

    def delete(self, request: Request, pk: str) -> Response:
        if not MODELS_AVAILABLE:
            return Response(
                {"detail": ("Park delete is not available because domain models " "are not imported.")},
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )
        park = self._get_park_or_404(pk)
        park.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


# --- Filter options ---------------------------------------------------------
@extend_schema(
    summary="Get comprehensive filter options for parks",
    responses={200: OpenApiTypes.OBJECT},
    tags=["Parks"],
)
class FilterOptionsAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request: Request) -> Response:
        """Return comprehensive filter options with Rich Choice Objects metadata."""
        # Import Rich Choice registry
        from apps.core.choices.registry import get_choices

        # Always get static choice definitions from Rich Choice Objects (primary source)
        park_types = get_choices("types", "parks")
        statuses = get_choices("statuses", "parks")

        # Convert Rich Choice Objects to frontend format with metadata
        park_types_data = [
            {
                "value": choice.value,
                "label": choice.label,
                "description": choice.description,
                "color": choice.metadata.get("color"),
                "icon": choice.metadata.get("icon"),
                "css_class": choice.metadata.get("css_class"),
                "sort_order": choice.metadata.get("sort_order", 0),
            }
            for choice in park_types
        ]

        statuses_data = [
            {
                "value": choice.value,
                "label": choice.label,
                "description": choice.description,
                "color": choice.metadata.get("color"),
                "icon": choice.metadata.get("icon"),
                "css_class": choice.metadata.get("css_class"),
                "sort_order": choice.metadata.get("sort_order", 0),
            }
            for choice in statuses
        ]

        # Get dynamic data from database if models are available
        if MODELS_AVAILABLE:
            # Add any dynamic data queries here
            pass

        return Response(
            {
                "park_types": park_types_data,
                "statuses": statuses_data,
                "continents": ["North America", "South America", "Europe", "Asia", "Africa", "Australia", "Antarctica"],
                "countries": [
                    "United States",
                    "Canada",
                    "United Kingdom",
                    "Germany",
                    "France",
                    "Japan",
                    "Australia",
                    "Brazil",
                ],
                "states": ["California", "Florida", "Ohio", "Pennsylvania", "Texas", "New York"],
                "cities": ["Orlando", "Los Angeles", "Cedar Point", "Sandusky"],
                "operators": [],
                "property_owners": [],
                "ranges": {
                    "rating": {"min": 1, "max": 10, "step": 0.1, "unit": "stars"},
                    "ride_count": {"min": 0, "max": 100, "step": 1, "unit": "rides"},
                    "coaster_count": {"min": 0, "max": 50, "step": 1, "unit": "coasters"},
                    "size_acres": {"min": 0, "max": 10000, "step": 1, "unit": "acres"},
                    "opening_year": {"min": 1800, "max": 2030, "step": 1, "unit": "year"},
                },
                "ordering_options": [
                    {"value": "name", "label": "Name (A-Z)"},
                    {"value": "-name", "label": "Name (Z-A)"},
                    {"value": "opening_date", "label": "Opening Date (Oldest First)"},
                    {"value": "-opening_date", "label": "Opening Date (Newest First)"},
                    {"value": "ride_count", "label": "Ride Count (Low to High)"},
                    {"value": "-ride_count", "label": "Ride Count (High to Low)"},
                    {"value": "coaster_count", "label": "Coaster Count (Low to High)"},
                    {"value": "-coaster_count", "label": "Coaster Count (High to Low)"},
                    {"value": "average_rating", "label": "Rating (Low to High)"},
                    {"value": "-average_rating", "label": "Rating (High to Low)"},
                    {"value": "size_acres", "label": "Size (Small to Large)"},
                    {"value": "-size_acres", "label": "Size (Large to Small)"},
                    {"value": "created_at", "label": "Added to Database (Oldest First)"},
                    {"value": "-created_at", "label": "Added to Database (Newest First)"},
                    {"value": "updated_at", "label": "Last Updated (Oldest First)"},
                    {"value": "-updated_at", "label": "Last Updated (Newest First)"},
                ],
            }
        )

        # Try to get dynamic options from database using Rich Choice Objects
        try:
            # Get rich choice objects from registry
            park_types = get_choices("types", "parks")
            statuses = get_choices("statuses", "parks")

            # Convert Rich Choice Objects to frontend format with metadata
            park_types_data = [
                {
                    "value": choice.value,
                    "label": choice.label,
                    "description": choice.description,
                    "color": choice.metadata.get("color"),
                    "icon": choice.metadata.get("icon"),
                    "css_class": choice.metadata.get("css_class"),
                    "sort_order": choice.metadata.get("sort_order", 0),
                }
                for choice in park_types
            ]

            statuses_data = [
                {
                    "value": choice.value,
                    "label": choice.label,
                    "description": choice.description,
                    "color": choice.metadata.get("color"),
                    "icon": choice.metadata.get("icon"),
                    "css_class": choice.metadata.get("css_class"),
                    "sort_order": choice.metadata.get("sort_order", 0),
                }
                for choice in statuses
            ]

            # Get location data from database
            continents = list(
                Park.objects.exclude(location__continent__isnull=True)
                .exclude(location__continent__exact="")
                .values_list("location__continent", flat=True)
                .distinct()
                .order_by("location__continent")
            )

            # Fallback to static list if no continents in database
            if not continents:
                continents = ["North America", "South America", "Europe", "Asia", "Africa", "Australia", "Antarctica"]

            countries = list(
                Park.objects.exclude(location__country__isnull=True)
                .exclude(location__country__exact="")
                .values_list("location__country", flat=True)
                .distinct()
                .order_by("location__country")
            )

            states = list(
                Park.objects.exclude(location__state__isnull=True)
                .exclude(location__state__exact="")
                .values_list("location__state", flat=True)
                .distinct()
                .order_by("location__state")
            )

            cities = list(
                Park.objects.exclude(location__city__isnull=True)
                .exclude(location__city__exact="")
                .values_list("location__city", flat=True)
                .distinct()
                .order_by("location__city")
            )

            # Get operators and property owners
            operators = list(
                Company.objects.filter(roles__contains=["OPERATOR"]).values("id", "name", "slug").order_by("name")
            )

            property_owners = list(
                Company.objects.filter(roles__contains=["PROPERTY_OWNER"]).values("id", "name", "slug").order_by("name")
            )

            # Calculate ranges from actual data
            park_stats = Park.objects.aggregate(
                min_rating=models.Min("average_rating"),
                max_rating=models.Max("average_rating"),
                min_ride_count=models.Min("ride_count"),
                max_ride_count=models.Max("ride_count"),
                min_coaster_count=models.Min("coaster_count"),
                max_coaster_count=models.Max("coaster_count"),
                min_size=models.Min("size_acres"),
                max_size=models.Max("size_acres"),
                min_year=models.Min("opening_date__year"),
                max_year=models.Max("opening_date__year"),
            )

            ranges = {
                "rating": {
                    "min": float(park_stats["min_rating"] or 1),
                    "max": float(park_stats["max_rating"] or 10),
                    "step": 0.1,
                    "unit": "stars",
                },
                "ride_count": {
                    "min": park_stats["min_ride_count"] or 0,
                    "max": park_stats["max_ride_count"] or 100,
                    "step": 1,
                    "unit": "rides",
                },
                "coaster_count": {
                    "min": park_stats["min_coaster_count"] or 0,
                    "max": park_stats["max_coaster_count"] or 50,
                    "step": 1,
                    "unit": "coasters",
                },
                "size_acres": {
                    "min": float(park_stats["min_size"] or 0),
                    "max": float(park_stats["max_size"] or 10000),
                    "step": 1,
                    "unit": "acres",
                },
                "opening_year": {
                    "min": park_stats["min_year"] or 1800,
                    "max": park_stats["max_year"] or 2030,
                    "step": 1,
                    "unit": "year",
                },
            }

            return Response(
                {
                    "park_types": park_types_data,
                    "statuses": statuses_data,
                    "continents": continents,
                    "countries": countries,
                    "states": states,
                    "cities": cities,
                    "operators": operators,
                    "property_owners": property_owners,
                    "ranges": ranges,
                    "ordering_options": [
                        {"value": "name", "label": "Name (A-Z)"},
                        {"value": "-name", "label": "Name (Z-A)"},
                        {"value": "opening_date", "label": "Opening Date (Oldest First)"},
                        {"value": "-opening_date", "label": "Opening Date (Newest First)"},
                        {"value": "ride_count", "label": "Ride Count (Low to High)"},
                        {"value": "-ride_count", "label": "Ride Count (High to Low)"},
                        {"value": "coaster_count", "label": "Coaster Count (Low to High)"},
                        {"value": "-coaster_count", "label": "Coaster Count (High to Low)"},
                        {"value": "average_rating", "label": "Rating (Low to High)"},
                        {"value": "-average_rating", "label": "Rating (High to Low)"},
                        {"value": "size_acres", "label": "Size (Small to Large)"},
                        {"value": "-size_acres", "label": "Size (Large to Small)"},
                        {"value": "created_at", "label": "Added to Database (Oldest First)"},
                        {"value": "-created_at", "label": "Added to Database (Newest First)"},
                        {"value": "updated_at", "label": "Last Updated (Oldest First)"},
                        {"value": "-updated_at", "label": "Last Updated (Newest First)"},
                    ],
                }
            )

        except Exception:
            # Fallback to static options if database query fails
            return Response(
                {
                    "park_types": [
                        {"value": "THEME_PARK", "label": "Theme Park"},
                        {"value": "AMUSEMENT_PARK", "label": "Amusement Park"},
                        {"value": "WATER_PARK", "label": "Water Park"},
                        {"value": "FAMILY_ENTERTAINMENT_CENTER", "label": "Family Entertainment Center"},
                        {"value": "CARNIVAL", "label": "Carnival"},
                        {"value": "FAIR", "label": "Fair"},
                        {"value": "PIER", "label": "Pier"},
                        {"value": "BOARDWALK", "label": "Boardwalk"},
                        {"value": "SAFARI_PARK", "label": "Safari Park"},
                        {"value": "ZOO", "label": "Zoo"},
                        {"value": "OTHER", "label": "Other"},
                    ],
                    "statuses": [
                        {"value": "OPERATING", "label": "Operating"},
                        {"value": "CLOSED_TEMP", "label": "Temporarily Closed"},
                        {"value": "CLOSED_PERM", "label": "Permanently Closed"},
                        {"value": "UNDER_CONSTRUCTION", "label": "Under Construction"},
                        {"value": "DEMOLISHED", "label": "Demolished"},
                        {"value": "RELOCATED", "label": "Relocated"},
                    ],
                    "continents": ["North America", "South America", "Europe", "Asia", "Africa", "Australia"],
                    "countries": ["United States", "Canada", "United Kingdom", "Germany", "France", "Japan"],
                    "states": ["California", "Florida", "Ohio", "Pennsylvania"],
                    "cities": ["Orlando", "Los Angeles", "Cedar Point"],
                    "operators": [],
                    "property_owners": [],
                    "ranges": {
                        "rating": {"min": 1, "max": 10, "step": 0.1, "unit": "stars"},
                        "ride_count": {"min": 0, "max": 100, "step": 1, "unit": "rides"},
                        "coaster_count": {"min": 0, "max": 50, "step": 1, "unit": "coasters"},
                        "size_acres": {"min": 0, "max": 10000, "step": 1, "unit": "acres"},
                        "opening_year": {"min": 1800, "max": 2030, "step": 1, "unit": "year"},
                    },
                    "ordering_options": [
                        {"value": "name", "label": "Name (A-Z)"},
                        {"value": "-name", "label": "Name (Z-A)"},
                        {"value": "opening_date", "label": "Opening Date (Oldest First)"},
                        {"value": "-opening_date", "label": "Opening Date (Newest First)"},
                        {"value": "ride_count", "label": "Ride Count (Low to High)"},
                        {"value": "-ride_count", "label": "Ride Count (High to Low)"},
                        {"value": "coaster_count", "label": "Coaster Count (Low to High)"},
                        {"value": "-coaster_count", "label": "Coaster Count (High to Low)"},
                        {"value": "average_rating", "label": "Rating (Low to High)"},
                        {"value": "-average_rating", "label": "Rating (High to Low)"},
                    ],
                }
            )


# --- Company search (autocomplete) -----------------------------------------
@extend_schema(
    summary="Search companies (operators/property owners) for autocomplete",
    parameters=[
        OpenApiParameter(
            name="q",
            location=OpenApiParameter.QUERY,
            type=OpenApiTypes.STR,
            description="Search query for company names",
        )
    ],
    responses={200: OpenApiTypes.OBJECT},
    tags=["Parks"],
)
class CompanySearchAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request: Request) -> Response:
        q = request.query_params.get("q", "")
        if not q:
            return Response([], status=status.HTTP_200_OK)

        if not MODELS_AVAILABLE or Company is None:
            # Provide helpful placeholder structure
            return Response(
                [
                    {"id": 1, "name": "Six Flags Entertainment", "slug": "six-flags"},
                    {"id": 2, "name": "Cedar Fair", "slug": "cedar-fair"},
                    {"id": 3, "name": "Disney Parks", "slug": "disney"},
                    {"id": 4, "name": "Universal Parks & Resorts", "slug": "universal"},
                    {"id": 5, "name": "SeaWorld Parks & Entertainment", "slug": "seaworld"},
                ]
            )

        try:
            # Search companies that can be operators or property owners
            qs = Company.objects.filter(
                Q(name__icontains=q) & (Q(roles__contains=["OPERATOR"]) | Q(roles__contains=["PROPERTY_OWNER"]))
            ).distinct()[:20]

            results = [
                {"id": c.id, "name": c.name, "slug": getattr(c, "slug", ""), "roles": getattr(c, "roles", [])}
                for c in qs
            ]
            return Response(results)
        except Exception:
            # Fallback to placeholder data
            return Response(
                [
                    {"id": 1, "name": "Six Flags Entertainment", "slug": "six-flags"},
                    {"id": 2, "name": "Cedar Fair", "slug": "cedar-fair"},
                    {"id": 3, "name": "Disney Parks", "slug": "disney"},
                ]
            )


# --- Search suggestions -----------------------------------------------------
@extend_schema(
    summary="Search suggestions for park search box",
    parameters=[OpenApiParameter(name="q", location=OpenApiParameter.QUERY, type=OpenApiTypes.STR)],
    tags=["Parks"],
)
class ParkSearchSuggestionsAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request: Request) -> Response:
        q = request.query_params.get("q", "")
        if not q:
            return Response([], status=status.HTTP_200_OK)

        # Very small suggestion implementation: look in park names if available
        if MODELS_AVAILABLE and Park is not None:
            qs = Park.objects.filter(name__icontains=q).values_list("name", flat=True)[:10]  # type: ignore
            return Response([{"suggestion": name} for name in qs])

        # Fallback suggestions
        fallback = [
            {"suggestion": f"{q} Park"},
            {"suggestion": f"{q} Theme Park"},
            {"suggestion": f"{q} Amusement Park"},
        ]
        return Response(fallback)


# --- Park image settings ---------------------------------------------------
@extend_schema(
    summary="Set park banner and card images",
    description="Set banner_image and card_image for a park from existing park photos",
    request=("ParkImageSettingsInputSerializer" if SERIALIZERS_AVAILABLE else OpenApiTypes.OBJECT),
    responses={
        200: ("ParkDetailOutputSerializer" if SERIALIZERS_AVAILABLE else OpenApiTypes.OBJECT),
        400: OpenApiTypes.OBJECT,
        404: OpenApiTypes.OBJECT,
    },
    tags=["Parks"],
)
class ParkImageSettingsAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def _get_park_or_404(self, pk: int) -> Any:
        if not MODELS_AVAILABLE:
            raise NotFound("Park models not available")
        try:
            return Park.objects.get(pk=pk)  # type: ignore
        except Park.DoesNotExist:  # type: ignore
            raise NotFound("Park not found") from None

    def patch(self, request: Request, pk: int) -> Response:
        """Set banner and card images for the park."""
        if not SERIALIZERS_AVAILABLE:
            return Response(
                {"detail": "Park image settings serializers not available."},
                status=status.HTTP_501_NOT_IMPLEMENTED,
            )

        park = self._get_park_or_404(pk)

        serializer = ParkImageSettingsInputSerializer(data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)

        # Update the park with the validated data
        for field, value in serializer.validated_data.items():
            setattr(park, field, value)

        park.save()

        # Return updated park data
        output_serializer = ParkDetailOutputSerializer(park, context={"request": request})
        return Response(output_serializer.data)


# --- Operator list ----------------------------------------------------------
@extend_schema(
    summary="List park operators",
    description="List all companies with OPERATOR role, including park counts.",
    responses={
        200: OpenApiTypes.OBJECT,
    },
    tags=["Parks"],
)
class OperatorListAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request: Request) -> Response:
        if not MODELS_AVAILABLE:
            return Response({"detail": "Models not available"}, status=status.HTTP_501_NOT_IMPLEMENTED)

        operators = (
            Company.objects.filter(roles__contains=["OPERATOR"])
            .annotate(park_count=Count("operated_parks"))
            .only("id", "name", "slug", "roles", "description")
            .order_by("name")
        )

        # Simple serialization
        data = [
            {
                "id": op.id,
                "name": op.name,
                "slug": op.slug,
                "description": op.description,
                "park_count": op.park_count,
            }
            for op in operators
        ]

        return Response({"results": data, "count": len(data)})
