import logging
import os
import secrets

from django.conf import settings
from django.core.cache import cache
from django.db.models import Q
from django.shortcuts import render
from django.views.generic import TemplateView

from apps.core.analytics import PageView
from apps.core.logging import log_exception
from apps.parks.models import Company, Park
from apps.rides.models import Ride

logger = logging.getLogger(__name__)


def handler404(request, exception):
    return render(request, "404.html", status=404)


def handler500(request):
    return render(request, "500.html", status=500)


class HomeView(TemplateView):
    template_name = "home.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Get stats
        context["stats"] = {
            "total_parks": Park.objects.count(),
            "ride_count": Ride.objects.count(),
            "coaster_count": Ride.objects.filter(category="RC").count(),
        }

        # Try to get trending items from cache first
        trending_parks = cache.get("trending_parks")
        trending_rides = cache.get("trending_rides")

        # If not in cache, get them directly and cache them
        if trending_parks is None:
            try:
                trending_parks = list(PageView.get_trending_items(Park, hours=24, limit=10))
                if trending_parks:
                    cache.set("trending_parks", trending_parks, 3600)  # Cache for 1 hour
                else:
                    # Fallback to highest rated parks if no trending data
                    trending_parks = Park.objects.exclude(average_rating__isnull=True).order_by("-average_rating")[:10]
            except Exception as e:
                log_exception(
                    logger,
                    e,
                    context={"operation": "get_trending_parks", "fallback": True},
                    request=self.request,
                )
                # Fallback to highest rated parks if trending calculation fails
                trending_parks = Park.objects.exclude(average_rating__isnull=True).order_by("-average_rating")[:10]

        if trending_rides is None:
            try:
                trending_rides = list(PageView.get_trending_items(Ride, hours=24, limit=10))
                if trending_rides:
                    cache.set("trending_rides", trending_rides, 3600)  # Cache for 1 hour
                else:
                    # Fallback to highest rated rides if no trending data
                    trending_rides = Ride.objects.exclude(average_rating__isnull=True).order_by("-average_rating")[:10]
            except Exception as e:
                log_exception(
                    logger,
                    e,
                    context={"operation": "get_trending_rides", "fallback": True},
                    request=self.request,
                )
                # Fallback to highest rated rides if trending calculation fails
                trending_rides = Ride.objects.exclude(average_rating__isnull=True).order_by("-average_rating")[:10]

        # Get highest rated items (mix of parks and rides)
        highest_rated_parks = list(
            Park.objects.exclude(average_rating__isnull=True).order_by("-average_rating")[:20]
        )  # Get more items to randomly select from

        highest_rated_rides = list(
            Ride.objects.exclude(average_rating__isnull=True).order_by("-average_rating")[:20]
        )  # Get more items to randomly select from

        # Combine and shuffle highest rated items
        all_highest_rated = highest_rated_parks + highest_rated_rides
        secrets.SystemRandom().shuffle(all_highest_rated)

        # Keep the same context variable names for template compatibility
        context["popular_parks"] = trending_parks
        context["popular_rides"] = trending_rides
        context["highest_rated"] = all_highest_rated[:10]  # Take first 10 after shuffling

        return context


class SearchView(TemplateView):
    template_name = "search_results.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        if query := self.request.GET.get("q", "").strip():
            # Search parks
            context["parks"] = (
                Park.objects.filter(
                    Q(name__icontains=query) | Q(location__icontains=query) | Q(description__icontains=query)
                )
                .select_related("operating_company")
                .prefetch_related("photos")[:10]
            )

            # Search rides
            context["rides"] = (
                Ride.objects.filter(
                    Q(name__icontains=query) | Q(description__icontains=query) | Q(manufacturer__name__icontains=query)
                )
                .select_related("park", "coaster_stats")
                .prefetch_related("photos")[:10]
            )

            # Search companies
            context["companies"] = Company.objects.filter(
                Q(name__icontains=query) | Q(description__icontains=query)
            ).prefetch_related("operated_parks", "owned_parks")[:10]

            logger.info(
                f"Search query: '{query}' returned {len(context['parks'])} parks, "
                f"{len(context['rides'])} rides, {len(context['companies'])} companies",
                extra={
                    "query": query,
                    "parks_count": len(context["parks"]),
                    "rides_count": len(context["rides"]),
                    "companies_count": len(context["companies"]),
                    "user_id": (self.request.user.id if self.request.user.is_authenticated else None),
                },
            )

        return context


def environment_and_settings_view(request):
    # Get all environment variables
    env_vars = dict(os.environ)

    # Get all Django settings as a dictionary
    settings_vars = {setting: getattr(settings, setting) for setting in dir(settings) if setting.isupper()}

    return render(
        request,
        "environment_and_settings.html",
        {"env_vars": env_vars, "settings_vars": settings_vars},
    )
