""" Serializers for Parks API following Django styleguide patterns. Separates Input and Output serializers for clear boundaries. """ from rest_framework import serializers from django.contrib.gis.geos import Point from ..models import Park, ParkArea, Company, ParkReview class ParkLocationOutputSerializer(serializers.Serializer): """Output serializer for park location data.""" latitude = serializers.SerializerMethodField() longitude = serializers.SerializerMethodField() city = serializers.SerializerMethodField() state = serializers.SerializerMethodField() country = serializers.SerializerMethodField() formatted_address = serializers.SerializerMethodField() def get_latitude(self, obj): if hasattr(obj, 'location') and obj.location: return obj.location.latitude return None def get_longitude(self, obj): if hasattr(obj, 'location') and obj.location: return obj.location.longitude return None def get_city(self, obj): if hasattr(obj, 'location') and obj.location: return obj.location.city return None def get_state(self, obj): if hasattr(obj, 'location') and obj.location: return obj.location.state return None def get_country(self, obj): if hasattr(obj, 'location') and obj.location: return obj.location.country return None def get_formatted_address(self, obj): if hasattr(obj, 'location') and obj.location: return obj.location.formatted_address return "" class CompanyOutputSerializer(serializers.Serializer): """Output serializer for company data.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() roles = serializers.ListField(child=serializers.CharField()) class ParkAreaOutputSerializer(serializers.Serializer): """Output serializer for park area data.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() description = serializers.CharField() class ParkListOutputSerializer(serializers.Serializer): """Output serializer for park list view.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() status = serializers.CharField() description = serializers.CharField() # Statistics average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True) coaster_count = serializers.IntegerField(allow_null=True) ride_count = serializers.IntegerField(allow_null=True) # Location (simplified for list view) location = ParkLocationOutputSerializer(allow_null=True) # Operator info operator = CompanyOutputSerializer() # Metadata created_at = serializers.DateTimeField() updated_at = serializers.DateTimeField() class ParkDetailOutputSerializer(serializers.Serializer): """Output serializer for park detail view.""" id = serializers.IntegerField() name = serializers.CharField() slug = serializers.CharField() status = serializers.CharField() description = serializers.CharField() # Details opening_date = serializers.DateField(allow_null=True) closing_date = serializers.DateField(allow_null=True) operating_season = serializers.CharField() size_acres = serializers.DecimalField(max_digits=10, decimal_places=2, allow_null=True) website = serializers.URLField() # Statistics average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True) coaster_count = serializers.IntegerField(allow_null=True) ride_count = serializers.IntegerField(allow_null=True) # Location (full details) location = ParkLocationOutputSerializer(allow_null=True) # Companies operator = CompanyOutputSerializer() property_owner = CompanyOutputSerializer(allow_null=True) # Areas areas = ParkAreaOutputSerializer(many=True) # Metadata created_at = serializers.DateTimeField() updated_at = serializers.DateTimeField() class ParkCreateInputSerializer(serializers.Serializer): """Input serializer for creating parks.""" name = serializers.CharField(max_length=255) description = serializers.CharField(allow_blank=True, default="") status = serializers.ChoiceField( choices=Park.STATUS_CHOICES, default="OPERATING" ) # Optional details opening_date = serializers.DateField(required=False, allow_null=True) closing_date = serializers.DateField(required=False, allow_null=True) operating_season = serializers.CharField(max_length=255, required=False, allow_blank=True) size_acres = serializers.DecimalField( max_digits=10, decimal_places=2, required=False, allow_null=True ) website = serializers.URLField(required=False, allow_blank=True) # Required operator operator_id = serializers.IntegerField() # Optional property owner property_owner_id = serializers.IntegerField(required=False, allow_null=True) def validate(self, data): """Cross-field validation.""" opening_date = data.get('opening_date') closing_date = data.get('closing_date') if opening_date and closing_date and closing_date < opening_date: raise serializers.ValidationError( "Closing date cannot be before opening date" ) return data class ParkUpdateInputSerializer(serializers.Serializer): """Input serializer for updating parks.""" name = serializers.CharField(max_length=255, required=False) description = serializers.CharField(allow_blank=True, required=False) status = serializers.ChoiceField( choices=Park.STATUS_CHOICES, required=False ) # Optional details opening_date = serializers.DateField(required=False, allow_null=True) closing_date = serializers.DateField(required=False, allow_null=True) operating_season = serializers.CharField(max_length=255, required=False, allow_blank=True) size_acres = serializers.DecimalField( max_digits=10, decimal_places=2, required=False, allow_null=True ) website = serializers.URLField(required=False, allow_blank=True) # Companies operator_id = serializers.IntegerField(required=False) property_owner_id = serializers.IntegerField(required=False, allow_null=True) def validate(self, data): """Cross-field validation.""" opening_date = data.get('opening_date') closing_date = data.get('closing_date') if opening_date and closing_date and closing_date < opening_date: raise serializers.ValidationError( "Closing date cannot be before opening date" ) return data class ParkFilterInputSerializer(serializers.Serializer): """Input serializer for park filtering and search.""" # Search search = serializers.CharField(required=False, allow_blank=True) # Status filter status = serializers.MultipleChoiceField( choices=Park.STATUS_CHOICES, required=False ) # Location filters country = serializers.CharField(required=False, allow_blank=True) state = serializers.CharField(required=False, allow_blank=True) city = serializers.CharField(required=False, allow_blank=True) # Rating filter min_rating = serializers.DecimalField( max_digits=3, decimal_places=2, required=False, min_value=1, max_value=10 ) # Size filter min_size_acres = serializers.DecimalField( max_digits=10, decimal_places=2, required=False, min_value=0 ) max_size_acres = serializers.DecimalField( max_digits=10, decimal_places=2, required=False, min_value=0 ) # Company filters operator_id = serializers.IntegerField(required=False) property_owner_id = serializers.IntegerField(required=False) # Ordering ordering = serializers.ChoiceField( choices=[ 'name', '-name', 'opening_date', '-opening_date', 'average_rating', '-average_rating', 'coaster_count', '-coaster_count', 'created_at', '-created_at' ], required=False, default='name' ) class ParkReviewOutputSerializer(serializers.Serializer): """Output serializer for park reviews.""" id = serializers.IntegerField() rating = serializers.IntegerField() title = serializers.CharField() content = serializers.CharField() visit_date = serializers.DateField() created_at = serializers.DateTimeField() # User info (limited for privacy) user = serializers.SerializerMethodField() def get_user(self, obj): return { 'username': obj.user.username, 'display_name': obj.user.get_full_name() or obj.user.username } class ParkStatsOutputSerializer(serializers.Serializer): """Output serializer for park statistics.""" total_parks = serializers.IntegerField() operating_parks = serializers.IntegerField() closed_parks = serializers.IntegerField() under_construction = serializers.IntegerField() # Averages average_rating = serializers.DecimalField(max_digits=3, decimal_places=2, allow_null=True) average_coaster_count = serializers.DecimalField(max_digits=5, decimal_places=2, allow_null=True) # Top countries top_countries = serializers.ListField(child=serializers.DictField()) # Recently added recently_added_count = serializers.IntegerField()