"""
Park API views for ThrillWiki API v1.

This module contains consolidated park photo viewset for the centralized API structure.
Enhanced from rogue implementation to maintain full feature parity.

Caching Strategy:
- HybridParkAPIView: 10 minutes (600s) - park lists are queried frequently
- ParkFilterMetadataAPIView: 30 minutes (1800s) - filter metadata is stable
- ParkPhotoViewSet.list/retrieve: 5 minutes (300s) - photos may be updated
- ParkPhotoViewSet.stats: 10 minutes (600s) - stats are aggregated
"""

import logging
from typing import Any, cast

from django.contrib.auth import get_user_model
from django.core.exceptions import PermissionDenied
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet

from apps.core.decorators.cache_decorators import cache_api_response
from apps.core.exceptions import (
    NotFoundError,
    ServiceError,
    ValidationException,
)
from apps.core.utils import capture_and_log
from apps.core.utils.error_handling import ErrorHandler
from apps.parks.models import Park, ParkPhoto
from apps.parks.services import ParkMediaService
from apps.parks.services.hybrid_loader import smart_park_loader

from .serializers import (
    HybridParkSerializer,
    ParkPhotoApprovalInputSerializer,
    ParkPhotoCreateInputSerializer,
    ParkPhotoListOutputSerializer,
    ParkPhotoOutputSerializer,
    ParkPhotoStatsOutputSerializer,
    ParkPhotoUpdateInputSerializer,
)

logger = logging.getLogger(__name__)
UserModel = get_user_model()


@extend_schema_view(
    list=extend_schema(
        summary="List park photos",
        description="Retrieve a paginated list of park photos with filtering capabilities.",
        responses={200: ParkPhotoListOutputSerializer(many=True)},
        tags=["Park Media"],
    ),
    create=extend_schema(
        summary="Upload park photo",
        description="Upload a new photo for a park. Requires authentication.",
        request=ParkPhotoCreateInputSerializer,
        responses={
            201: ParkPhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    ),
    retrieve=extend_schema(
        summary="Get park photo details",
        description="Retrieve detailed information about a specific park photo.",
        responses={
            200: ParkPhotoOutputSerializer,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    ),
    update=extend_schema(
        summary="Update park photo",
        description="Update park photo information. Requires authentication and ownership or admin privileges.",
        request=ParkPhotoUpdateInputSerializer,
        responses={
            200: ParkPhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    ),
    partial_update=extend_schema(
        summary="Partially update park photo",
        description="Partially update park photo information. Requires authentication and ownership or admin privileges.",
        request=ParkPhotoUpdateInputSerializer,
        responses={
            200: ParkPhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    ),
    destroy=extend_schema(
        summary="Delete park photo",
        description="Delete a park photo. Requires authentication and ownership or admin privileges.",
        responses={
            204: None,
            401: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    ),
)
class ParkPhotoViewSet(ModelViewSet):
    """
    Enhanced ViewSet for managing park photos with full feature parity.

    Provides CRUD operations for park photos with proper permission checking.
    Uses ParkMediaService for business logic operations.
    Includes advanced features like bulk approval and statistics.
    """

    lookup_field = "id"

    def get_permissions(self):
        """Set permissions based on action."""
        permission_classes = [AllowAny] if self.action in ["list", "retrieve", "stats"] else [IsAuthenticated]
        return [permission() for permission in permission_classes]

    def get_queryset(self):  # type: ignore[override]
        """Get photos for the current park with optimized queries."""
        queryset = ParkPhoto.objects.select_related("park", "park__operator", "uploaded_by")

        # If park_pk is provided in URL kwargs, filter by park
        # If park_pk is provided in URL kwargs, filter by park
        park_pk = self.kwargs.get("park_pk")
        if park_pk:
            if str(park_pk).isdigit():
                queryset = queryset.filter(park_id=park_pk)
            else:
                queryset = queryset.filter(park__slug=park_pk)

        return queryset.order_by("-created_at")

    def get_serializer_class(self):  # type: ignore[override]
        """Return appropriate serializer based on action."""
        if self.action == "list":
            return ParkPhotoListOutputSerializer
        elif self.action == "create":
            return ParkPhotoCreateInputSerializer
        elif self.action in ["update", "partial_update"]:
            return ParkPhotoUpdateInputSerializer
        else:
            return ParkPhotoOutputSerializer

    def perform_create(self, serializer):
        """Create a new park photo using ParkMediaService."""
        park_id = self.kwargs.get("park_pk")
        if not park_id:
            raise ValidationError("Park ID/Slug is required")

        try:
            park = Park.objects.get(pk=park_id) if str(park_id).isdigit() else Park.objects.get(slug=park_id)

            # Use real park ID
            park_id = park.id
        except Park.DoesNotExist:
            raise ValidationError("Park not found") from None

        try:
            # Use the service to create the photo with proper business logic
            service = cast(Any, ParkMediaService())
            photo = service.create_photo(
                park_id=park_id,
                uploaded_by=self.request.user,
                **serializer.validated_data,
            )

            # Set the instance for the serializer response
            serializer.instance = photo

        except (ValidationException, ValidationError) as e:
            logger.warning(f"Validation error creating park photo: {e}")
            raise ValidationError(str(e)) from None
        except ServiceError as e:
            capture_and_log(e, 'Create park photo', source='api')
            raise ValidationError(f"Failed to create photo: {str(e)}") from None

    def perform_update(self, serializer):
        """Update park photo with permission checking."""
        instance = self.get_object()

        # Check permissions - allow owner or staff
        if not (self.request.user == instance.uploaded_by or cast(Any, self.request.user).is_staff):
            raise PermissionDenied("You can only edit your own photos or be an admin.")

        # Handle primary photo logic using service
        if serializer.validated_data.get("is_primary", False):
            try:
                ParkMediaService().set_primary_photo(park_id=instance.park_id, photo_id=instance.id)
                # Remove is_primary from validated_data since service handles it
                if "is_primary" in serializer.validated_data:
                    del serializer.validated_data["is_primary"]
            except (ValidationException, ValidationError) as e:
                logger.warning(f"Validation error setting primary photo: {e}")
                raise ValidationError(str(e)) from None
            except ServiceError as e:
                capture_and_log(e, 'Set primary park photo', source='api')
                raise ValidationError(f"Failed to set primary photo: {str(e)}") from None

    def perform_destroy(self, instance):
        """Delete park photo with permission checking."""
        # Check permissions - allow owner or staff
        if not (self.request.user == instance.uploaded_by or cast(Any, self.request.user).is_staff):
            raise PermissionDenied("You can only delete your own photos or be an admin.")

        # Delete from Cloudflare first if image exists
        if instance.image:
            try:
                from django_cloudflareimages_toolkit.services import (
                    CloudflareImagesService,
                )

                service = CloudflareImagesService()
                service.delete_image(instance.image)
                logger.info(f"Successfully deleted park photo from Cloudflare: {instance.image.cloudflare_id}")
            except ImportError:
                logger.warning("CloudflareImagesService not available")
            except ServiceError as e:
                capture_and_log(e, 'Delete park photo from Cloudflare', source='api', severity='low')
                # Continue with database deletion even if Cloudflare deletion fails

        try:
            ParkMediaService().delete_photo(instance.id, deleted_by=cast(UserModel, self.request.user))
        except ServiceError as e:
            capture_and_log(e, 'Delete park photo', source='api')
            raise ValidationError(f"Failed to delete photo: {str(e)}") from None

    @extend_schema(
        summary="Set photo as primary",
        description="Set this photo as the primary photo for the park",
        responses={
            200: OpenApiTypes.OBJECT,
            400: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    )
    @action(detail=True, methods=["post"])
    def set_primary(self, request, **kwargs):
        """Set this photo as the primary photo for the park."""
        photo = self.get_object()

        # Check permissions - allow owner or staff
        if not (request.user == photo.uploaded_by or cast(Any, request.user).is_staff):
            raise PermissionDenied("You can only modify your own photos or be an admin.")

        try:
            ParkMediaService().set_primary_photo(park_id=photo.park_id, photo_id=photo.id)

            # Refresh the photo instance
            photo.refresh_from_db()
            serializer = self.get_serializer(photo)

            return Response(
                {
                    "detail": "Photo set as primary successfully",
                    "photo": serializer.data,
                },
                status=status.HTTP_200_OK,
            )

        except (ValidationException, ValidationError) as e:
            logger.warning(f"Validation error setting primary photo: {e}")
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to set primary photo",
                status_code=status.HTTP_400_BAD_REQUEST,
            )
        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to set primary photo",
                status_code=status.HTTP_400_BAD_REQUEST,
            )

    @extend_schema(
        summary="Bulk approve/reject photos",
        description="Bulk approve or reject multiple park photos (admin only)",
        request=ParkPhotoApprovalInputSerializer,
        responses={
            200: OpenApiTypes.OBJECT,
            400: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    )
    @action(detail=False, methods=["post"], permission_classes=[IsAuthenticated])
    def bulk_approve(self, request, **kwargs):
        """Bulk approve or reject multiple photos (admin only)."""
        if not cast(Any, request.user).is_staff:
            raise PermissionDenied("Only administrators can approve photos.")

        serializer = ParkPhotoApprovalInputSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        validated_data = cast(dict, getattr(serializer, "validated_data", {}))
        photo_ids = validated_data.get("photo_ids")
        approve = validated_data.get("approve")
        park_id = self.kwargs.get("park_pk")

        if photo_ids is None or approve is None:
            return Response(
                {"detail": "Missing required fields: photo_ids and/or approve."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            # Filter photos to only those belonging to this park (if park_pk provided)
            photos_queryset = ParkPhoto.objects.filter(id__in=photo_ids)
            if park_id:
                if str(park_id).isdigit():
                    photos_queryset = photos_queryset.filter(park_id=park_id)
                else:
                    photos_queryset = photos_queryset.filter(park__slug=park_id)

            updated_count = photos_queryset.update(is_approved=approve)

            return Response(
                {
                    "detail": f"Successfully {'approved' if approve else 'rejected'} {updated_count} photos",
                    "updated_count": updated_count,
                },
                status=status.HTTP_200_OK,
            )

        except (ValidationException, ValidationError) as e:
            logger.warning(f"Validation error in bulk photo approval: {e}")
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to update photos",
                status_code=status.HTTP_400_BAD_REQUEST,
            )
        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to update photos",
                status_code=status.HTTP_400_BAD_REQUEST,
            )

    @extend_schema(
        summary="Get park photo statistics",
        description="Get photo statistics for the park",
        responses={
            200: ParkPhotoStatsOutputSerializer,
            404: OpenApiTypes.OBJECT,
            500: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    )
    @action(detail=False, methods=["get"])
    def stats(self, request, **kwargs):
        """Get photo statistics for the park."""
        park_pk = self.kwargs.get("park_pk")
        park = None
        if park_pk:
            try:
                park = Park.objects.get(pk=park_pk) if str(park_pk).isdigit() else Park.objects.get(slug=park_pk)
            except Park.DoesNotExist:
                return ErrorHandler.handle_api_error(
                    NotFoundError(f"Park with id/slug {park_pk} not found"),
                    user_message="Park not found",
                    status_code=status.HTTP_404_NOT_FOUND,
                )

        try:
            if park is not None:
                stats = ParkMediaService().get_photo_stats(park=park)
            else:
                stats = ParkMediaService().get_photo_stats(park=cast(Park, None))
            serializer = ParkPhotoStatsOutputSerializer(stats)

            return Response(serializer.data, status=status.HTTP_200_OK)

        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to get photo statistics",
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    # Legacy compatibility action using the legacy set_primary logic
    @extend_schema(
        summary="Set photo as primary (legacy)",
        description="Legacy set primary action for backwards compatibility",
        responses={
            200: OpenApiTypes.OBJECT,
            400: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    )
    @action(detail=True, methods=["post"])
    def set_primary_legacy(self, request, id=None):
        """Legacy set primary action for backwards compatibility."""
        photo = self.get_object()
        if not (request.user == photo.uploaded_by or request.user.has_perm("parks.change_parkphoto")):
            return Response(
                {"detail": "You do not have permission to edit photos for this park."},
                status=status.HTTP_403_FORBIDDEN,
            )
        try:
            ParkMediaService().set_primary_photo(park_id=photo.park_id, photo_id=photo.id)
            return Response({"detail": "Photo set as primary successfully."})
        except (ValidationException, ValidationError) as e:
            logger.warning(f"Validation error in set_primary_photo: {str(e)}")
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to set primary photo",
                status_code=status.HTTP_400_BAD_REQUEST,
            )
        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to set primary photo",
                status_code=status.HTTP_400_BAD_REQUEST,
            )

    @extend_schema(
        summary="Save Cloudflare image as park photo",
        description="Save a Cloudflare image as a park photo after direct upload to Cloudflare",
        request=OpenApiTypes.OBJECT,
        responses={
            201: ParkPhotoOutputSerializer,
            400: OpenApiTypes.OBJECT,
            401: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT,
        },
        tags=["Park Media"],
    )
    @action(detail=False, methods=["post"])
    def save_image(self, request, **kwargs):
        """Save a Cloudflare image as a park photo after direct upload to Cloudflare."""
        park_pk = self.kwargs.get("park_pk")
        if not park_pk:
            return Response(
                {"detail": "Park ID is required"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            park = Park.objects.get(pk=park_pk) if str(park_pk).isdigit() else Park.objects.get(slug=park_pk)
        except Park.DoesNotExist:
            return Response(
                {"detail": "Park not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        cloudflare_image_id = request.data.get("cloudflare_image_id")
        if not cloudflare_image_id:
            return Response(
                {"detail": "cloudflare_image_id is required"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            # Import CloudflareImage model and service
            from django.utils import timezone
            from django_cloudflareimages_toolkit.models import CloudflareImage
            from django_cloudflareimages_toolkit.services import CloudflareImagesService

            # Always fetch the latest image data from Cloudflare API
            # Get image details from Cloudflare API
            service = CloudflareImagesService()
            image_data = service.get_image(cloudflare_image_id)

            if not image_data:
                return ErrorHandler.handle_api_error(
                    NotFoundError("Image not found in Cloudflare"),
                    user_message="Image not found in Cloudflare",
                    status_code=status.HTTP_400_BAD_REQUEST,
                )

            # Try to find existing CloudflareImage record by cloudflare_id
            cloudflare_image = None
            try:
                cloudflare_image = CloudflareImage.objects.get(cloudflare_id=cloudflare_image_id)

                # Update existing record with latest data from Cloudflare
                cloudflare_image.status = "uploaded"
                cloudflare_image.uploaded_at = timezone.now()
                cloudflare_image.metadata = image_data.get("meta", {})
                # Extract variants from nested result structure
                cloudflare_image.variants = image_data.get("result", {}).get("variants", [])
                cloudflare_image.cloudflare_metadata = image_data
                cloudflare_image.width = image_data.get("width")
                cloudflare_image.height = image_data.get("height")
                cloudflare_image.format = image_data.get("format", "")
                cloudflare_image.save()

            except CloudflareImage.DoesNotExist:
                # Create new CloudflareImage record from API response
                cloudflare_image = CloudflareImage.objects.create(
                    cloudflare_id=cloudflare_image_id,
                    user=request.user,
                    status="uploaded",
                    upload_url="",  # Not needed for uploaded images
                    expires_at=timezone.now() + timezone.timedelta(days=365),  # Set far future expiry
                    uploaded_at=timezone.now(),
                    metadata=image_data.get("meta", {}),
                    # Extract variants from nested result structure
                    variants=image_data.get("result", {}).get("variants", []),
                    cloudflare_metadata=image_data,
                    width=image_data.get("width"),
                    height=image_data.get("height"),
                    format=image_data.get("format", ""),
                )

            # Create the park photo with the CloudflareImage reference
            photo = ParkPhoto.objects.create(
                park=park,
                image=cloudflare_image,
                uploaded_by=request.user,
                caption=request.data.get("caption", ""),
                alt_text=request.data.get("alt_text", ""),
                photo_type=request.data.get("photo_type", "exterior"),
                is_primary=request.data.get("is_primary", False),
                is_approved=False,  # Default to requiring approval
            )

            # Handle primary photo logic if requested
            if request.data.get("is_primary", False):
                try:
                    ParkMediaService().set_primary_photo(park_id=park.id, photo_id=photo.id)
                except ServiceError as e:
                    capture_and_log(e, 'Set primary park photo for saved image', source='api', severity='low')
                    # Don't fail the entire operation, just log the error

            serializer = ParkPhotoOutputSerializer(photo, context={"request": request})
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        except ImportError as e:
            capture_and_log(e, 'Cloudflare service import', source='api')
            return ErrorHandler.handle_api_error(
                ServiceError("Cloudflare Images service not available"),
                user_message="Image upload service not available",
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        except (ValidationException, ValidationError) as e:
            logger.warning(f"Validation error saving park photo: {e}")
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to save photo",
                status_code=status.HTTP_400_BAD_REQUEST,
            )
        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to save photo",
                status_code=status.HTTP_400_BAD_REQUEST,
            )


@extend_schema_view(
    get=extend_schema(
        summary="Get parks with hybrid filtering",
        description="Retrieve parks with intelligent hybrid filtering strategy. Automatically chooses between client-side and server-side filtering based on data size.",
        parameters=[
            OpenApiParameter(
                "status",
                OpenApiTypes.STR,
                description="Filter by park status (comma-separated for multiple)",
            ),
            OpenApiParameter(
                "park_type",
                OpenApiTypes.STR,
                description="Filter by park type (comma-separated for multiple)",
            ),
            OpenApiParameter(
                "country",
                OpenApiTypes.STR,
                description="Filter by country (comma-separated for multiple)",
            ),
            OpenApiParameter(
                "state",
                OpenApiTypes.STR,
                description="Filter by state (comma-separated for multiple)",
            ),
            OpenApiParameter("opening_year_min", OpenApiTypes.INT, description="Minimum opening year"),
            OpenApiParameter("opening_year_max", OpenApiTypes.INT, description="Maximum opening year"),
            OpenApiParameter(
                "size_min",
                OpenApiTypes.NUMBER,
                description="Minimum park size in acres",
            ),
            OpenApiParameter(
                "size_max",
                OpenApiTypes.NUMBER,
                description="Maximum park size in acres",
            ),
            OpenApiParameter("rating_min", OpenApiTypes.NUMBER, description="Minimum average rating"),
            OpenApiParameter("rating_max", OpenApiTypes.NUMBER, description="Maximum average rating"),
            OpenApiParameter("ride_count_min", OpenApiTypes.INT, description="Minimum ride count"),
            OpenApiParameter("ride_count_max", OpenApiTypes.INT, description="Maximum ride count"),
            OpenApiParameter(
                "coaster_count_min",
                OpenApiTypes.INT,
                description="Minimum coaster count",
            ),
            OpenApiParameter(
                "coaster_count_max",
                OpenApiTypes.INT,
                description="Maximum coaster count",
            ),
            OpenApiParameter(
                "operator",
                OpenApiTypes.STR,
                description="Filter by operator slug (comma-separated for multiple)",
            ),
            OpenApiParameter(
                "search",
                OpenApiTypes.STR,
                description="Search query for park names, descriptions, locations, and operators",
            ),
            OpenApiParameter(
                "offset",
                OpenApiTypes.INT,
                description="Offset for progressive loading (server-side pagination)",
            ),
        ],
        responses={
            200: {
                "description": "Parks data with hybrid filtering metadata",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "parks": {
                                    "type": "array",
                                    "items": {"$ref": "#/components/schemas/HybridParkSerializer"},
                                },
                                "total_count": {"type": "integer"},
                                "strategy": {
                                    "type": "string",
                                    "enum": ["client_side", "server_side"],
                                    "description": "Filtering strategy used",
                                },
                                "has_more": {
                                    "type": "boolean",
                                    "description": "Whether more data is available for progressive loading",
                                },
                                "next_offset": {
                                    "type": "integer",
                                    "nullable": True,
                                    "description": "Next offset for progressive loading",
                                },
                                "filter_metadata": {
                                    "type": "object",
                                    "description": "Available filter options and ranges",
                                },
                            },
                        }
                    }
                },
            }
        },
        tags=["Parks"],
    )
)
class HybridParkAPIView(APIView):
    """
    Hybrid Park API View with intelligent filtering strategy.

    Automatically chooses between client-side and server-side filtering
    based on data size and complexity. Provides progressive loading
    for large datasets and complete data for smaller sets.

    Caching: 10-minute timeout (600s) - park lists are queried frequently
    but need to reflect new additions within reasonable time.
    """

    permission_classes = [AllowAny]

    @cache_api_response(timeout=600, key_prefix="hybrid_parks")
    def get(self, request):
        """Get parks with hybrid filtering strategy."""
        # Extract filters from query parameters
        filters = self._extract_filters(request.query_params)

        # Check if this is a progressive load request
        offset = request.query_params.get("offset")
        if offset is not None:
            try:
                offset = int(offset)
            except ValueError:
                return ErrorHandler.handle_api_error(
                    ValidationException("Invalid offset parameter"),
                    user_message="Invalid offset parameter",
                    status_code=status.HTTP_400_BAD_REQUEST,
                )

        try:
            if offset is not None:
                # Get progressive load data
                data = smart_park_loader.get_progressive_load(offset, filters)
            else:
                # Get initial load data
                data = smart_park_loader.get_initial_load(filters)

            # Serialize the parks data
            serializer = HybridParkSerializer(data["parks"], many=True)

            # Prepare response
            response_data = {
                "parks": serializer.data,
                "total_count": data["total_count"],
                "strategy": data.get("strategy", "server_side"),
                "has_more": data.get("has_more", False),
                "next_offset": data.get("next_offset"),
            }

            # Include filter metadata for initial loads
            if "filter_metadata" in data:
                response_data["filter_metadata"] = data["filter_metadata"]

            return Response(response_data, status=status.HTTP_200_OK)

        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to load parks",
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _extract_filters(self, query_params):
        """Extract and parse filters from query parameters."""
        filters = {}

        # Handle comma-separated list parameters
        list_params = ["status", "park_type", "country", "state", "operator"]
        for param in list_params:
            value = query_params.get(param)
            if value:
                filters[param] = [v.strip() for v in value.split(",") if v.strip()]

        # Handle integer parameters
        int_params = [
            "opening_year_min",
            "opening_year_max",
            "ride_count_min",
            "ride_count_max",
            "coaster_count_min",
            "coaster_count_max",
        ]
        for param in int_params:
            value = query_params.get(param)
            if value:
                try:  # noqa: SIM105
                    filters[param] = int(value)
                except ValueError:
                    pass  # Skip invalid integer values

        # Handle float parameters
        float_params = ["size_min", "size_max", "rating_min", "rating_max"]
        for param in float_params:
            value = query_params.get(param)
            if value:
                try:  # noqa: SIM105
                    filters[param] = float(value)
                except ValueError:
                    pass  # Skip invalid float values

        # Handle search parameter
        search = query_params.get("search")
        if search:
            filters["search"] = search.strip()

        return filters


@extend_schema_view(
    get=extend_schema(
        summary="Get park filter metadata",
        description="Get available filter options and ranges for parks filtering.",
        parameters=[
            OpenApiParameter(
                "scoped",
                OpenApiTypes.BOOL,
                description="Whether to scope metadata to current filters",
            ),
        ],
        responses={
            200: {
                "description": "Filter metadata",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "categorical": {
                                    "type": "object",
                                    "properties": {
                                        "countries": {
                                            "type": "array",
                                            "items": {"type": "string"},
                                        },
                                        "states": {
                                            "type": "array",
                                            "items": {"type": "string"},
                                        },
                                        "park_types": {
                                            "type": "array",
                                            "items": {"type": "string"},
                                        },
                                        "statuses": {
                                            "type": "array",
                                            "items": {"type": "string"},
                                        },
                                        "operators": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "name": {"type": "string"},
                                                    "slug": {"type": "string"},
                                                },
                                            },
                                        },
                                    },
                                },
                                "ranges": {
                                    "type": "object",
                                    "properties": {
                                        "opening_year": {
                                            "type": "object",
                                            "properties": {
                                                "min": {
                                                    "type": "integer",
                                                    "nullable": True,
                                                },
                                                "max": {
                                                    "type": "integer",
                                                    "nullable": True,
                                                },
                                            },
                                        },
                                        "size_acres": {
                                            "type": "object",
                                            "properties": {
                                                "min": {
                                                    "type": "number",
                                                    "nullable": True,
                                                },
                                                "max": {
                                                    "type": "number",
                                                    "nullable": True,
                                                },
                                            },
                                        },
                                        "average_rating": {
                                            "type": "object",
                                            "properties": {
                                                "min": {
                                                    "type": "number",
                                                    "nullable": True,
                                                },
                                                "max": {
                                                    "type": "number",
                                                    "nullable": True,
                                                },
                                            },
                                        },
                                        "ride_count": {
                                            "type": "object",
                                            "properties": {
                                                "min": {
                                                    "type": "integer",
                                                    "nullable": True,
                                                },
                                                "max": {
                                                    "type": "integer",
                                                    "nullable": True,
                                                },
                                            },
                                        },
                                        "coaster_count": {
                                            "type": "object",
                                            "properties": {
                                                "min": {
                                                    "type": "integer",
                                                    "nullable": True,
                                                },
                                                "max": {
                                                    "type": "integer",
                                                    "nullable": True,
                                                },
                                            },
                                        },
                                    },
                                },
                                "total_count": {"type": "integer"},
                            },
                        }
                    }
                },
            }
        },
        tags=["Parks"],
    )
)
class ParkFilterMetadataAPIView(APIView):
    """
    API view for getting park filter metadata.

    Provides information about available filter options and ranges
    to help build dynamic filter interfaces.

    Caching: 30-minute timeout (1800s) - filter metadata is stable
    and only changes when new entities are added.
    """

    permission_classes = [AllowAny]

    @cache_api_response(timeout=1800, key_prefix="park_filter_metadata")
    def get(self, request):
        """Get park filter metadata."""
        # Check if metadata should be scoped to current filters
        scoped = request.query_params.get("scoped", "").lower() == "true"
        filters = None

        if scoped:
            filters = self._extract_filters(request.query_params)

        try:
            # Get filter metadata
            metadata = smart_park_loader.get_filter_metadata(filters)
            return Response(metadata, status=status.HTTP_200_OK)

        except ServiceError as e:
            return ErrorHandler.handle_api_error(
                e,
                user_message="Failed to get filter metadata",
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _extract_filters(self, query_params):
        """Extract and parse filters from query parameters."""
        # Reuse the same filter extraction logic
        view = HybridParkAPIView()
        return view._extract_filters(query_params)
