"""
Django management command to calculate new content.

This replaces the Celery task for calculating new content.
Run with: uv run manage.py calculate_new_content
"""

import logging
from datetime import datetime, timedelta
from typing import Any

from django.core.cache import cache
from django.core.management.base import BaseCommand, CommandError
from django.db.models import Q
from django.utils import timezone

from apps.parks.models import Park
from apps.rides.models import Ride
from apps.core.utils import capture_and_log

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = "Calculate new content and cache results"

    def add_arguments(self, parser):
        parser.add_argument(
            "--content-type",
            type=str,
            default="all",
            choices=["all", "parks", "rides"],
            help="Type of content to calculate (default: all)",
        )
        parser.add_argument(
            "--days-back",
            type=int,
            default=30,
            help="Number of days to look back for new content (default: 30)",
        )
        parser.add_argument(
            "--limit",
            type=int,
            default=50,
            help="Maximum number of results to calculate (default: 50)",
        )
        parser.add_argument("--verbose", action="store_true", help="Enable verbose output")

    def handle(self, *args, **options):
        content_type = options["content_type"]
        days_back = options["days_back"]
        limit = options["limit"]
        verbose = options["verbose"]

        if verbose:
            self.stdout.write(f"Starting new content calculation for {content_type}")

        try:
            cutoff_date = timezone.now() - timedelta(days=days_back)
            new_items = []

            if content_type in ["all", "parks"]:
                parks = self._get_new_parks(cutoff_date, limit if content_type == "parks" else limit * 2)
                new_items.extend(parks)
                if verbose:
                    self.stdout.write(f"Found {len(parks)} new parks")

            if content_type in ["all", "rides"]:
                rides = self._get_new_rides(cutoff_date, limit if content_type == "rides" else limit * 2)
                new_items.extend(rides)
                if verbose:
                    self.stdout.write(f"Found {len(rides)} new rides")

            # Sort by date added (most recent first) and apply limit
            new_items.sort(key=lambda x: x.get("date_added", ""), reverse=True)
            new_items = new_items[:limit]

            # Format results for API consumption
            formatted_results = self._format_new_content_results(new_items)

            # Cache results
            cache_key = f"new_content:calculated:{content_type}:{days_back}:{limit}"
            cache.set(cache_key, formatted_results, 1800)  # Cache for 30 minutes

            self.stdout.write(
                self.style.SUCCESS(f"Successfully calculated {len(formatted_results)} new items for {content_type}")
            )

            if verbose:
                for item in formatted_results[:5]:  # Show first 5 items
                    self.stdout.write(f"  {item['name']} ({item['park']}) - opened: {item['date_opened']}")

        except Exception as e:
            capture_and_log(e, 'Calculate new content', source='management', severity='high')
            raise CommandError(f"Failed to calculate new content: {e}") from None

    def _get_new_parks(self, cutoff_date: datetime, limit: int) -> list[dict[str, Any]]:
        """Get recently added parks using real data."""
        new_parks = (
            Park.objects.filter(
                Q(created_at__gte=cutoff_date) | Q(opening_date__gte=cutoff_date.date()),
                status="OPERATING",
            )
            .select_related("location", "operator")
            .order_by("-created_at", "-opening_date")[:limit]
        )

        results = []
        for park in new_parks:
            date_added = park.opening_date or park.created_at
            if date_added and isinstance(date_added, datetime):
                date_added = date_added.date()

            opening_date = getattr(park, "opening_date", None)
            if opening_date and isinstance(opening_date, datetime):
                opening_date = opening_date.date()

            results.append(
                {
                    "content_object": park,
                    "content_type": "park",
                    "id": park.pk,
                    "name": park.name,
                    "slug": park.slug,
                    "park": park.name,  # For parks, park field is the park name itself
                    "category": "park",
                    "date_added": date_added.isoformat() if date_added else "",
                    "date_opened": opening_date.isoformat() if opening_date else "",
                    "url": park.url,
                }
            )

        return results

    def _get_new_rides(self, cutoff_date: datetime, limit: int) -> list[dict[str, Any]]:
        """Get recently added rides using real data."""
        new_rides = (
            Ride.objects.filter(
                Q(created_at__gte=cutoff_date) | Q(opening_date__gte=cutoff_date.date()),
                status="OPERATING",
            )
            .select_related("park", "park__location")
            .order_by("-created_at", "-opening_date")[:limit]
        )

        results = []
        for ride in new_rides:
            date_added = getattr(ride, "opening_date", None) or getattr(ride, "created_at", None)
            if date_added and isinstance(date_added, datetime):
                date_added = date_added.date()

            opening_date = getattr(ride, "opening_date", None)
            if opening_date and isinstance(opening_date, datetime):
                opening_date = opening_date.date()

            results.append(
                {
                    "content_object": ride,
                    "content_type": "ride",
                    "id": ride.pk,
                    "name": ride.name,
                    "slug": ride.slug,
                    "park": ride.park.name if ride.park else "",
                    "category": "ride",
                    "date_added": date_added.isoformat() if date_added else "",
                    "date_opened": opening_date.isoformat() if opening_date else "",
                    "url": ride.url,
                    "park_url": ride.park.url if ride.park else "",
                }
            )

        return results

    def _format_new_content_results(self, new_items: list[dict[str, Any]]) -> list[dict[str, Any]]:
        """Format new content results for frontend consumption."""
        formatted_results = []

        for item in new_items:
            try:
                # Format exactly as frontend expects
                formatted_item = {
                    "id": item["id"],
                    "name": item["name"],
                    "park": item["park"],
                    "category": item["category"],
                    "date_added": item["date_added"],
                    "date_opened": item["date_opened"],
                    "slug": item["slug"],
                    "url": item["url"],
                }

                # Add park_url for rides
                if item.get("park_url"):
                    formatted_item["park_url"] = item["park_url"]

                formatted_results.append(formatted_item)

            except Exception as e:
                logger.warning(f"Error formatting new content item: {e}")

        return formatted_results
