"""
Demonstration script showing practical usage of the RoadTripService.

This script demonstrates real-world scenarios for using the OSM Road Trip Service
in the ThrillWiki application.
"""

from apps.parks.models import Park
from apps.parks.services import RoadTripService
import os
import django

# Setup Django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.django.local")
django.setup()

# New small helpers and constant to simplify functions and avoid repeated literals
MAGIC_KINGDOM = "Magic Kingdom"


def _format_coords(coords):
	"""
	Return (lat, lon) tuple or None for a coords object/sequence.
	Accepts objects with .latitude/.longitude or indexable (lat, lon).
	"""
	if not coords:
		return None
	lat = getattr(coords, "latitude", None)
	lon = getattr(coords, "longitude", None)
	if lat is not None and lon is not None:
		return (lat, lon)
	# Fallback to indexable
	try:
		return (coords[0], coords[1])
	except Exception:
		return None


def _print_route_summary(route, indent="   "):
	"""Safely print route summary fields if route is present."""
	if not route:
		return
	# Use attributes with fallback to dict keys if needed
	formatted_distance = getattr(route, "formatted_distance", None) or route.get(
		"formatted_distance", "N/A"
	) if isinstance(route, dict) else getattr(route, "formatted_distance", "N/A")
	formatted_duration = getattr(route, "formatted_duration", None) or route.get(
		"formatted_duration", "N/A"
	) if isinstance(route, dict) else getattr(route, "formatted_duration", "N/A")
	print(f"{indent}{formatted_distance}, {formatted_duration}")


def demo_florida_theme_park_trip():
	"""
	Demonstrate planning a Florida theme park road trip.
	"""
	print("🏖️ Florida Theme Park Road Trip Planner")
	print("=" * 50)

	service = RoadTripService()

	# Define Florida theme parks with addresses
	florida_parks = [
		(MAGIC_KINGDOM, "Magic Kingdom Dr, Orlando, FL 32830"),
		("Universal Studios Florida", "6000 Universal Blvd, Orlando, FL 32819"),
		("SeaWorld Orlando", "7007 Sea World Dr, Orlando, FL 32821"),
		("Busch Gardens Tampa", "10165 McKinley Dr, Tampa, FL 33612"),
	]

	print("Planning trip for these Florida parks:")
	park_coords = {}

	# small helper to geocode and store
	def _geocode_and_store(name, address):
		print(f"\n📍 Geocoding {name}...")
		coords = service.geocode_address(address)
		if coords:
			latlon = _format_coords(coords)
			if latlon:
				park_coords[name] = coords
				print(f"   ✅ Located at {latlon[0]:.4f}, {latlon[1]:.4f}")
				return True
		print(f"   ❌ Could not geocode {address}")
		return False

	for name, address in florida_parks:
		_geocode_and_store(name, address)

	if len(park_coords) < 2:
		print("❌ Need at least 2 parks to plan a trip")
		return

	# Calculate distances between all parks
	print("\n🗺️ Distance Matrix:")
	park_names = list(park_coords.keys())

	for i, park1 in enumerate(park_names):
		for j, park2 in enumerate(park_names):
			if i < j:  # Only calculate each pair once
				route = service.calculate_route(park_coords[park1], park_coords[park2])
				if route:
					print(f"   {park1} ↔ {park2}")
					_print_route_summary(route, indent="      ")

	# Find central park for radiating searches
	print(f"\n🎢 Parks within 100km of {MAGIC_KINGDOM}:")
	magic_kingdom_coords = park_coords.get(MAGIC_KINGDOM)
	if magic_kingdom_coords:
		for name, coords in park_coords.items():
			if name != MAGIC_KINGDOM:
				route = service.calculate_route(magic_kingdom_coords, coords)
				if route:
					_print_route_summary(route, indent=f"   {name}: ")


def demo_cross_country_road_trip():
	"""
	Demonstrate planning a cross-country theme park road trip.
	"""
	print("\n\n🇺🇸 Cross-Country Theme Park Road Trip")
	print("=" * 50)

	service = RoadTripService()

	# Major theme parks across the US
	major_parks = [
		("Disneyland", "1313 Disneyland Dr, Anaheim, CA 92802"),
		("Cedar Point", "1 Cedar Point Dr, Sandusky, OH 44870"),
		("Six Flags Magic Mountain", "26101 Magic Mountain Pkwy, Valencia, CA 91355"),
		("Walt Disney World", "Walt Disney World Resort, Orlando, FL 32830"),
	]

	print("Geocoding major US theme parks:")
	park_coords = {}

	for name, address in major_parks:
		print(f"\n📍 {name}...")
		coords = service.geocode_address(address)
		if coords:
			park_coords[name] = coords
			latlon = _format_coords(coords)
			if latlon:
				print(f"   ✅ {latlon[0]:.4f}, {latlon[1]:.4f}")

	if len(park_coords) >= 3:
		# Calculate an optimized route if we have DB parks
		print("\n🛣️ Optimized Route Planning:")
		print("Note: This would work with actual Park objects from the database")

		# Show distances for a potential route
		route_order = [
			"Disneyland",
			"Six Flags Magic Mountain",
			"Cedar Point",
			"Walt Disney World",
		]
		total_distance = 0
		total_time = 0

		for i in range(len(route_order) - 1):
			from_park = route_order[i]
			to_park = route_order[i + 1]

			if from_park in park_coords and to_park in park_coords:
				route = service.calculate_route(park_coords[from_park], park_coords[to_park])
				if route:
					total_distance += getattr(route, "distance_km", 0) or route.get("distance_km", 0) if isinstance(route, dict) else getattr(route, "distance_km", 0)
					total_time += getattr(route, "duration_minutes", 0) or route.get("duration_minutes", 0) if isinstance(route, dict) else getattr(route, "duration_minutes", 0)
					print(f"   {i + 1}. {from_park} → {to_park}")
					_print_route_summary(route, indent="      ")

		print("\n📊 Trip Summary:")
		print(f"   Total Distance: {total_distance:.1f}km")
		hours = total_time // 60
		mins = total_time % 60
		print(f"   Total Driving Time: {hours}h {mins}min")
		# avoid division by zero
		legs = max(1, len(route_order) - 1)
		print(f"   Average Distance per Leg: {total_distance / legs:.1f}km")


def demo_database_integration():
	"""
	Demonstrate working with actual parks from the database.
	"""
	print("\n\n🗄️ Database Integration Demo")
	print("=" * 50)

	service = RoadTripService()

	# Get parks that have location data
	parks_with_location = Park.objects.filter(location__point__isnull=False).select_related("location")[:5]

	if not parks_with_location:
		print("❌ No parks with location data found in database")
		return

	print(f"Found {len(parks_with_location)} parks with location data:")

	for park in parks_with_location:
		coords = getattr(park, "coordinates", None)
		latlon = _format_coords(coords)
		if latlon:
			print(f"   🎢 {park.name}: {latlon[0]:.4f}, {latlon[1]:.4f}")

	# Demonstrate nearby park search
	if len(parks_with_location) >= 1:
		center_park = parks_with_location[0]
		print(f"\n🔍 Finding parks within 500km of {center_park.name}:")

		nearby_parks = service.get_park_distances(center_park, radius_km=500)

		if nearby_parks:
			print(f"   Found {len(nearby_parks)} nearby parks:")
			for result in nearby_parks[:3]:  # Show top 3
				park = result.get("park") if isinstance(result, dict) else getattr(result, "park", None)
				# use safe formatted strings
				formatted_distance = result.get("formatted_distance", "N/A") if isinstance(result, dict) else getattr(result, "formatted_distance", "N/A")
				formatted_duration = result.get("formatted_duration", "N/A") if isinstance(result, dict) else getattr(result, "formatted_duration", "N/A")
				if park:
					print(f"   📍 {park.name}: {formatted_distance} ({formatted_duration})")
		else:
			print("   No nearby parks found (may need larger radius)")

	# Demonstrate multi-park trip planning
	if len(parks_with_location) >= 3:
		selected_parks = list(parks_with_location)[:3]
		print("\n🗺️ Planning optimized trip for 3 parks:")

		for park in selected_parks:
			print(f"   - {park.name}")

		trip = service.create_multi_park_trip(selected_parks)

		if trip:
			print("\n✅ Optimized Route:")
			print(f"   Total Distance: {getattr(trip, 'formatted_total_distance', 'N/A')}")
			print(f"   Total Duration: {getattr(trip, 'formatted_total_duration', 'N/A')}")
			print("   Route:")

			for i, leg in enumerate(getattr(trip, "legs", []) or [], 1):
				from_park = getattr(leg, "from_park", None)
				to_park = getattr(leg, "to_park", None)
				route = getattr(leg, "route", None)
				if from_park and to_park:
					print(f"      {i}. {from_park.name} → {to_park.name}")
					_print_route_summary(route, indent="         ")
		else:
			print("   ❌ Could not optimize trip route")


def demo_geocoding_fallback():
	"""
	Demonstrate geocoding parks that don't have coordinates.
	"""
	print("\n\n🌍 Geocoding Demo")
	print("=" * 50)

	service = RoadTripService()

	# Get parks without location data
	parks_without_coords = Park.objects.filter(location__point__isnull=True).select_related("location")[:3]

	if not parks_without_coords:
		print("✅ All parks already have coordinates")
		return

	print(f"Found {len(parks_without_coords)} parks without coordinates:")

	for park in parks_without_coords:
		print(f"\n🎢 {park.name}")

		location = getattr(park, "location", None)
		if location:
			# use getattr to avoid attribute errors
			address_parts = [
				getattr(park, "name", None),
				getattr(location, "street_address", None),
				getattr(location, "city", None),
				getattr(location, "state", None),
				getattr(location, "country", None),
			]
			address = ", ".join(part for part in address_parts if part)
			print(f"   Address: {address}")

			# Try to geocode
			success = service.geocode_park_if_needed(park)
			if success:
				coords = getattr(park, "coordinates", None)
				latlon = _format_coords(coords)
				if latlon:
					print(f"   ✅ Geocoded to: {latlon[0]:.4f}, {latlon[1]:.4f}")
				else:
					print("   ✅ Geocoded but coordinates unavailable")
			else:
				print("   ❌ Geocoding failed")
		else:
			print("   ❌ No location data available")


def demo_cache_performance():
	"""
	Demonstrate caching performance benefits.
	"""
	print("\n\n⚡ Cache Performance Demo")
	print("=" * 50)

	service = RoadTripService()

	import time

	# Test address for geocoding
	test_address = "Disneyland, Anaheim, CA"

	print(f"Testing cache performance with: {test_address}")

	# First request (cache miss)
	print("\n1️⃣ First request (cache miss):")
	start_time = time.time()
	coords1 = service.geocode_address(test_address)
	first_duration = time.time() - start_time

	if coords1:
		latlon = _format_coords(coords1)
		if latlon:
			print(f"   ✅ Result: {latlon[0]:.4f}, {latlon[1]:.4f}")
		else:
			print("   ✅ Result obtained")
		print(f"   ⏱️ Duration: {first_duration:.2f} seconds")

	# Second request (cache hit)
	print("\n2️⃣ Second request (cache hit):")
	start_time = time.time()
	coords2 = service.geocode_address(test_address)
	second_duration = time.time() - start_time

	if coords2:
		latlon2 = _format_coords(coords2)
		if latlon2:
			print(f"   ✅ Result: {latlon2[0]:.4f}, {latlon2[1]:.4f}")
		else:
			print("   ✅ Result obtained")
		print(f"   ⏱️ Duration: {second_duration:.2f} seconds")

		if first_duration > second_duration and second_duration > 0:
			speedup = first_duration / second_duration
			print(f"   🚀 Cache speedup: {speedup:.1f}x faster")

		# Compare coordinates if both present
		if coords1 and coords2:
			latlon1 = _format_coords(coords1)
			latlon2 = _format_coords(coords2)
			if latlon1 and latlon2 and latlon1 == latlon2:
				print("   ✅ Results identical (cache working)")


def main():
	"""
	Run all demonstration scenarios.
	"""
	print("🎢 ThrillWiki Road Trip Service Demo")
	print("This demo shows practical usage scenarios for the OSM Road Trip Service")

	try:
		demo_florida_theme_park_trip()
		demo_cross_country_road_trip()
		demo_database_integration()
		demo_geocoding_fallback()
		demo_cache_performance()

		print("\n" + "=" * 50)
		print("🎉 Demo completed successfully!")
		print("\nThe Road Trip Service is ready for integration into ThrillWiki!")
		print("\nKey Features Demonstrated:")
		print("✅ Geocoding theme park addresses")
		print("✅ Route calculation with distance/time")
		print("✅ Multi-park trip optimization")
		print("✅ Database integration with Park models")
		print("✅ Caching for performance")
		print("✅ Rate limiting for OSM compliance")
		print("✅ Error handling and fallbacks")

	except Exception as e:
		print(f"\n❌ Demo failed with error: {e}")
		import traceback

		traceback.print_exc()


if __name__ == "__main__":
	main()
