from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.db import IntegrityError from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone from django.views import View from django.views.generic import ListView, TemplateView, UpdateView from .forms import SavedSearchForm, SavedSearchUpdateForm from .models import FavoritePlayer, SavedSearch from .services.saved_searches import extract_filters_from_params, saved_search_to_querystring class ScoutingHomeView(LoginRequiredMixin, TemplateView): template_name = "scouting/index.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["saved_searches"] = SavedSearch.objects.filter(user=self.request.user).order_by("-updated_at") context["favorites"] = ( FavoritePlayer.objects.filter(user=self.request.user) .select_related("player", "player__nationality", "player__nominal_position", "player__inferred_role") .order_by("-created_at") ) return context class SavedSearchCreateView(LoginRequiredMixin, View): def post(self, request, *args, **kwargs): form = SavedSearchForm(request.POST) if not form.is_valid(): if request.headers.get("HX-Request") == "true": return render( request, "scouting/partials/save_search_feedback.html", {"ok": False, "message": "Invalid name or visibility values."}, ) messages.error(request, "Could not save search.") return redirect("players:index") filters = extract_filters_from_params(request.POST) if not filters: message = "No valid filters to save from current search." if request.headers.get("HX-Request") == "true": return render( request, "scouting/partials/save_search_feedback.html", {"ok": False, "message": message}, ) messages.error(request, message) return redirect("players:index") saved_search = form.save(commit=False) saved_search.user = request.user saved_search.filters = filters try: saved_search.save() except IntegrityError: message = "A saved search with this name already exists." if request.headers.get("HX-Request") == "true": return render( request, "scouting/partials/save_search_feedback.html", {"ok": False, "message": message}, ) messages.error(request, message) return redirect("players:index") message = f"Saved search '{saved_search.name}' created." if request.headers.get("HX-Request") == "true": return render( request, "scouting/partials/save_search_feedback.html", {"ok": True, "message": message}, ) messages.success(request, message) return redirect("scouting:index") class SavedSearchUpdateView(LoginRequiredMixin, UpdateView): model = SavedSearch form_class = SavedSearchUpdateForm template_name = "scouting/saved_search_edit.html" def get_queryset(self): return SavedSearch.objects.filter(user=self.request.user) def get_success_url(self): messages.success(self.request, "Saved search updated.") return reverse("scouting:index") class SavedSearchDeleteView(LoginRequiredMixin, View): def post(self, request, pk, *args, **kwargs): saved_search = get_object_or_404(SavedSearch, pk=pk, user=request.user) saved_search.delete() if request.headers.get("HX-Request") == "true": saved_searches = SavedSearch.objects.filter(user=request.user).order_by("-updated_at") return render( request, "scouting/partials/saved_search_table.html", {"saved_searches": saved_searches}, ) messages.success(request, "Saved search deleted.") return redirect("scouting:index") class SavedSearchRunView(LoginRequiredMixin, View): def get(self, request, pk, *args, **kwargs): saved_search = get_object_or_404(SavedSearch, pk=pk, user=request.user) query = saved_search_to_querystring(saved_search.filters) saved_search.last_run_at = timezone.now() saved_search.save(update_fields=["last_run_at"]) target = reverse("players:index") return redirect(f"{target}?{query}" if query else target) class WatchlistView(LoginRequiredMixin, ListView): model = FavoritePlayer context_object_name = "favorites" template_name = "scouting/watchlist.html" def get_queryset(self): return ( FavoritePlayer.objects.filter(user=self.request.user) .select_related("player", "player__nationality", "player__nominal_position", "player__inferred_role") .order_by("-created_at") ) class FavoriteToggleView(LoginRequiredMixin, View): def post(self, request, player_id, *args, **kwargs): from apps.players.models import Player player = get_object_or_404(Player, pk=player_id) next_url = request.POST.get("next") or request.META.get("HTTP_REFERER") or reverse("players:index") favorite, created = FavoritePlayer.objects.get_or_create(user=request.user, player=player) if not created: favorite.delete() is_favorite = created if request.headers.get("HX-Request") == "true": return render( request, "scouting/partials/favorite_button.html", { "player": player, "is_favorite": is_favorite, "next_url": next_url, }, ) return redirect(next_url) class SavedSearchListView(LoginRequiredMixin, ListView): model = SavedSearch context_object_name = "saved_searches" template_name = "scouting/saved_search_list.html" def get_queryset(self): return SavedSearch.objects.filter(user=self.request.user).order_by("-updated_at")