"""
Maps domain serializers for ThrillWiki API v1.

This module contains all serializers related to map functionality,
including location data, search results, and clustering.
"""

from drf_spectacular.utils import (
    OpenApiExample,
    extend_schema_field,
    extend_schema_serializer,
)
from rest_framework import serializers

# === MAP LOCATION SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Map Location Example",
            summary="Example map location response",
            description="A location point on the map",
            value={
                "id": 1,
                "type": "park",
                "name": "Cedar Point",
                "slug": "cedar-point",
                "latitude": 41.4793,
                "longitude": -82.6833,
                "status": "OPERATING",
                "location": {
                    "city": "Sandusky",
                    "state": "Ohio",
                    "country": "United States",
                },
                "stats": {
                    "coaster_count": 17,
                    "ride_count": 70,
                    "average_rating": 4.5,
                },
            },
        )
    ]
)
class MapLocationSerializer(serializers.Serializer):
    """Serializer for individual map locations (parks and rides)."""

    id = serializers.IntegerField()
    type = serializers.CharField()  # 'park' or 'ride'
    name = serializers.CharField()
    slug = serializers.CharField()
    latitude = serializers.FloatField(allow_null=True)
    longitude = serializers.FloatField(allow_null=True)
    status = serializers.CharField()

    # Location details
    location = serializers.SerializerMethodField()

    # Statistics
    stats = serializers.SerializerMethodField()

    @extend_schema_field(serializers.DictField())
    def get_location(self, obj) -> dict:
        """Get location information."""
        if hasattr(obj, "location") and obj.location:
            return {
                "city": obj.location.city,
                "state": obj.location.state,
                "country": obj.location.country,
                "formatted_address": obj.location.formatted_address,
            }
        return {}

    @extend_schema_field(serializers.DictField())
    def get_stats(self, obj) -> dict:
        """Get relevant statistics based on object type."""
        if obj._meta.model_name == "park":
            return {
                "coaster_count": obj.coaster_count or 0,
                "ride_count": obj.ride_count or 0,
                "average_rating": (float(obj.average_rating) if obj.average_rating else None),
            }
        elif obj._meta.model_name == "ride":
            return {
                "category": obj.get_category_display() if obj.category else None,
                "average_rating": (float(obj.average_rating) if obj.average_rating else None),
                "park_name": obj.park.name if obj.park else None,
            }
        return {}


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Map Cluster Example",
            summary="Example map cluster response",
            description="A cluster of locations on the map",
            value={
                "id": "cluster_1",
                "type": "cluster",
                "latitude": 41.5,
                "longitude": -82.7,
                "count": 5,
                "bounds": {
                    "north": 41.6,
                    "south": 41.4,
                    "east": -82.6,
                    "west": -82.8,
                },
            },
        )
    ]
)
class MapClusterSerializer(serializers.Serializer):
    """Serializer for map clusters."""

    id = serializers.CharField()
    type = serializers.CharField(default="cluster")
    latitude = serializers.FloatField()
    longitude = serializers.FloatField()
    count = serializers.IntegerField()
    bounds = serializers.DictField()


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Map Locations Response Example",
            summary="Example map locations response",
            description="Response containing locations and optional clusters",
            value={
                "status": "success",
                "data": {
                    "locations": [
                        {
                            "id": 1,
                            "type": "park",
                            "name": "Cedar Point",
                            "slug": "cedar-point",
                            "latitude": 41.4793,
                            "longitude": -82.6833,
                            "status": "OPERATING",
                        }
                    ],
                    "clusters": [],
                    "bounds": {
                        "north": 41.5,
                        "south": 41.4,
                        "east": -82.6,
                        "west": -82.8,
                    },
                    "total_count": 1,
                    "clustered": False,
                },
            },
        )
    ]
)
class MapLocationsResponseSerializer(serializers.Serializer):
    """Response serializer for map locations endpoint."""

    status = serializers.CharField(default="success")
    locations = serializers.ListField(child=serializers.DictField())
    clusters = serializers.ListField(child=serializers.DictField(), default=list)
    bounds = serializers.DictField(default=dict)
    total_count = serializers.IntegerField(default=0)
    clustered = serializers.BooleanField(default=False)


# === MAP SEARCH SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Map Search Result Example",
            summary="Example map search result",
            description="A search result for map locations",
            value={
                "id": 1,
                "type": "park",
                "name": "Cedar Point",
                "slug": "cedar-point",
                "latitude": 41.4793,
                "longitude": -82.6833,
                "location": {
                    "city": "Sandusky",
                    "state": "Ohio",
                    "country": "United States",
                },
                "relevance_score": 0.95,
            },
        )
    ]
)
class MapSearchResultSerializer(serializers.Serializer):
    """Serializer for map search results."""

    id = serializers.IntegerField()
    type = serializers.CharField()
    name = serializers.CharField()
    slug = serializers.CharField()
    latitude = serializers.FloatField(allow_null=True)
    longitude = serializers.FloatField(allow_null=True)
    location = serializers.SerializerMethodField()
    relevance_score = serializers.FloatField(required=False)

    @extend_schema_field(serializers.DictField())
    def get_location(self, obj) -> dict:
        """Get location information."""
        if hasattr(obj, "location") and obj.location:
            return {
                "city": obj.location.city,
                "state": obj.location.state,
                "country": obj.location.country,
            }
        return {}


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Map Search Response Example",
            summary="Example map search response",
            description="Response containing search results",
            value={
                "status": "success",
                "data": {
                    "results": [
                        {
                            "id": 1,
                            "type": "park",
                            "name": "Cedar Point",
                            "slug": "cedar-point",
                            "latitude": 41.4793,
                            "longitude": -82.6833,
                        }
                    ],
                    "query": "cedar point",
                    "total_count": 1,
                    "page": 1,
                    "page_size": 20,
                },
            },
        )
    ]
)
class MapSearchResponseSerializer(serializers.Serializer):
    """Response serializer for map search endpoint."""

    status = serializers.CharField(default="success")
    results = serializers.ListField(child=serializers.DictField())
    query = serializers.CharField()
    total_count = serializers.IntegerField(default=0)
    page = serializers.IntegerField(default=1)
    page_size = serializers.IntegerField(default=20)


# === MAP DETAIL SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Map Location Detail Example",
            summary="Example map location detail response",
            description="Detailed information about a specific location",
            value={
                "id": 1,
                "type": "park",
                "name": "Cedar Point",
                "slug": "cedar-point",
                "description": "America's Roller Coast",
                "latitude": 41.4793,
                "longitude": -82.6833,
                "status": "OPERATING",
                "location": {
                    "street_address": "1 Cedar Point Dr",
                    "city": "Sandusky",
                    "state": "Ohio",
                    "country": "United States",
                    "postal_code": "44870",
                    "formatted_address": "1 Cedar Point Dr, Sandusky, Ohio, 44870, United States",
                },
                "stats": {
                    "coaster_count": 17,
                    "ride_count": 70,
                    "average_rating": 4.5,
                },
                "nearby_locations": [],
            },
        )
    ]
)
class MapLocationDetailSerializer(serializers.Serializer):
    """Serializer for detailed map location information."""

    id = serializers.IntegerField()
    type = serializers.CharField()
    name = serializers.CharField()
    slug = serializers.CharField()
    description = serializers.CharField()
    latitude = serializers.FloatField(allow_null=True)
    longitude = serializers.FloatField(allow_null=True)
    status = serializers.CharField()

    # Detailed location information
    location = serializers.SerializerMethodField()

    # Statistics
    stats = serializers.SerializerMethodField()

    # Nearby locations
    nearby_locations = serializers.SerializerMethodField()

    @extend_schema_field(serializers.DictField())
    def get_location(self, obj) -> dict:
        """Get detailed location information."""
        if hasattr(obj, "location") and obj.location:
            return {
                "street_address": obj.location.street_address,
                "city": obj.location.city,
                "state": obj.location.state,
                "country": obj.location.country,
                "postal_code": obj.location.postal_code,
                "formatted_address": obj.location.formatted_address,
            }
        return {}

    @extend_schema_field(serializers.DictField())
    def get_stats(self, obj) -> dict:
        """Get detailed statistics based on object type."""
        if obj._meta.model_name == "park":
            return {
                "coaster_count": obj.coaster_count or 0,
                "ride_count": obj.ride_count or 0,
                "average_rating": (float(obj.average_rating) if obj.average_rating else None),
                "size_acres": float(obj.size_acres) if obj.size_acres else None,
                "opening_date": (obj.opening_date.isoformat() if obj.opening_date else None),
            }
        elif obj._meta.model_name == "ride":
            return {
                "category": obj.get_category_display() if obj.category else None,
                "average_rating": (float(obj.average_rating) if obj.average_rating else None),
                "park_name": obj.park.name if obj.park else None,
                "opening_date": (obj.opening_date.isoformat() if obj.opening_date else None),
                "manufacturer": obj.manufacturer.name if obj.manufacturer else None,
            }
        return {}

    @extend_schema_field(serializers.ListField(child=serializers.DictField()))
    def get_nearby_locations(self, obj) -> list:
        """Get nearby locations (placeholder for now)."""
        # See FUTURE_WORK.md - THRILLWIKI-107 for implementation plan
        return []


# === INPUT SERIALIZERS ===


class MapBoundsInputSerializer(serializers.Serializer):
    """Input serializer for map bounds queries."""

    north = serializers.FloatField(min_value=-90, max_value=90)
    south = serializers.FloatField(min_value=-90, max_value=90)
    east = serializers.FloatField(min_value=-180, max_value=180)
    west = serializers.FloatField(min_value=-180, max_value=180)

    def validate(self, attrs):
        """Validate that bounds make geographic sense."""
        if attrs["north"] <= attrs["south"]:
            raise serializers.ValidationError("North bound must be greater than south bound")

        # Handle longitude wraparound (e.g., crossing the international date line)
        # For now, we'll require west < east for simplicity
        if attrs["west"] >= attrs["east"]:
            raise serializers.ValidationError("West bound must be less than east bound")

        return attrs


class MapSearchInputSerializer(serializers.Serializer):
    """Input serializer for map search queries."""

    q = serializers.CharField(min_length=1, max_length=255)
    types = serializers.CharField(required=False, allow_blank=True)
    bounds = MapBoundsInputSerializer(required=False)
    page = serializers.IntegerField(min_value=1, default=1)
    page_size = serializers.IntegerField(min_value=1, max_value=100, default=20)

    def validate_types(self, value):
        """Validate location types."""
        if not value:
            return []

        valid_types = ["park", "ride"]
        types = [t.strip().lower() for t in value.split(",")]

        for location_type in types:
            if location_type not in valid_types:
                raise serializers.ValidationError(
                    f"Invalid location type: {location_type}. Valid types: {', '.join(valid_types)}"
                )

        return types
