from django.views.generic import DetailView, ListView, CreateView
from django.shortcuts import get_object_or_404, render
from django.core.serializers.json import DjangoJSONEncoder
from django.urls import reverse
from django.db.models import Q
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
from .models import Park, ParkArea
from rides.models import Ride
from core.views import SlugRedirectMixin
from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, InlineEditMixin, HistoryMixin
from moderation.models import EditSubmission
import pycountry

class ParkCreateView(LoginRequiredMixin, CreateView):
    model = Park
    template_name = 'parks/park_form.html'
    fields = ['name', 'location', 'country', 'description', 'owner', 'status', 
             'opening_date', 'closing_date', 'operating_season', 'size_acres', 'website']

    def form_valid(self, form):
        # If user is moderator or above, save directly
        if self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']:
            self.object = form.save()
            return HttpResponseRedirect(self.get_success_url())
        
        # Otherwise, create a submission
        cleaned_data = form.cleaned_data.copy()
        # Convert model instances to IDs for JSON serialization
        if cleaned_data.get('owner'):
            cleaned_data['owner'] = cleaned_data['owner'].id

        submission = EditSubmission.objects.create(
            user=self.request.user,
            content_type=ContentType.objects.get_for_model(Park),
            submission_type='CREATE',
            changes=cleaned_data,
            reason=self.request.POST.get('reason', ''),
            source=self.request.POST.get('source', '')
        )
        return HttpResponseRedirect(reverse('park_list'))

    def get_success_url(self):
        return reverse('park_detail', kwargs={'slug': self.object.slug})

def search_countries(request):
    query = request.GET.get('q', '').strip()
    countries = []
    
    if query:
        # Use pycountry's search functionality for fuzzy matching
        try:
            # Try exact search first
            country = pycountry.countries.get(name=query)
            if country:
                countries = [country]
            else:
                # If no exact match, try fuzzy search
                countries = pycountry.countries.search_fuzzy(query)
        except LookupError:
            # If search fails, fallback to manual filtering
            countries = [
                country for country in pycountry.countries
                if query.lower() in country.name.lower()
            ]
    
    return render(request, 'parks/partials/country_search_results.html', {
        'countries': countries[:10]  # Limit to top 10 results
    })

def select_country(request):
    if request.method == 'POST':
        country = request.POST.get('country', '')
        return HttpResponse(country)
    return HttpResponse('Invalid request', status=400)

class ParkDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, InlineEditMixin, HistoryMixin, DetailView):
    model = Park
    template_name = 'parks/park_detail.html'
    context_object_name = 'park'

    def get_object(self, queryset=None):
        if queryset is None:
            queryset = self.get_queryset()
        slug = self.kwargs.get(self.slug_url_kwarg)
        # Try to get by current or historical slug
        return self.model.get_by_slug(slug)[0]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['rides'] = Ride.objects.filter(
            park=self.object
        ).select_related('coaster_stats')
        context['areas'] = ParkArea.objects.filter(park=self.object)
        return context

    def get_redirect_url_pattern(self):
        return 'park_detail'

class ParkAreaDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, InlineEditMixin, HistoryMixin, DetailView):
    model = ParkArea
    template_name = 'parks/area_detail.html'
    context_object_name = 'area'
    slug_url_kwarg = 'area_slug'

    def get_object(self, queryset=None):
        if queryset is None:
            queryset = self.get_queryset()
        park_slug = self.kwargs.get('park_slug')
        area_slug = self.kwargs.get('area_slug')
        # Try to get by current or historical slug
        obj, is_old_slug = self.model.get_by_slug(area_slug)
        if obj.park.slug != park_slug:
            raise self.model.DoesNotExist("Park slug doesn't match")
        return obj

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['rides'] = Ride.objects.filter(
            area=self.object
        ).select_related('coaster_stats')
        return context

    def get_redirect_url_pattern(self):
        return 'park_detail'

    def get_redirect_url_kwargs(self):
        return {
            'park_slug': self.object.park.slug,
            'area_slug': self.object.slug
        }

class ParkListView(ListView):
    model = Park
    template_name = 'parks/park_list.html'
    context_object_name = 'parks'

    def get_queryset(self):
        queryset = Park.objects.select_related('owner').prefetch_related('photos', 'rides')
        
        search = self.request.GET.get('search', '').strip() or None
        location = self.request.GET.get('location', '').strip() or None
        status = self.request.GET.get('status', '').strip() or None
        
        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) | 
                Q(location__icontains=search)
            )
        if location:
            queryset = queryset.filter(location=location)
        if status:
            queryset = queryset.filter(status=status)
            
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get unique locations for filter dropdown
        context['locations'] = list(Park.objects.values_list('location', flat=True)
                                  .distinct().order_by('location'))
        
        # Add current filter values to context
        context['current_filters'] = {
            'search': self.request.GET.get('search', ''),
            'location': self.request.GET.get('location', ''),
            'status': self.request.GET.get('status', '')
        }
        
        return context

    def get(self, request, *args, **kwargs):
        # Check if this is an HTMX request
        if request.htmx:
            # If it is, return just the parks list partial
            self.template_name = 'parks/partials/park_list.html'
        return super().get(request, *args, **kwargs)
