from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic.base import View

from aircox.models import Episode, Program, StaticPage, Track
from aircox import forms, filters, permissions

from .mixins import VueFormDataMixin
from .page import attach, PageDetailView, PageListView, PageUpdateView


__all__ = (
    "EpisodeDetailView",
    "EpisodeListView",
    "PodcastListView",
    "EpisodeCreateView",
    "EpisodeUpdateView",
)


class EpisodeDetailView(PageDetailView):
    model = Episode

    def can_edit(self, obj):
        return permissions.program.can(self.request.user, "update", obj)

    def get_context_data(self, **kwargs):
        if "tracks" not in kwargs:
            kwargs["tracks"] = self.object.track_set.order_by("position")
        return super().get_context_data(**kwargs)

    def get_related_queryset(self):
        return (
            self.get_queryset().parent(self.object.parent).exclude(pk=self.object.pk).published().order_by("-pub_date")
        )

    def get_related_url(self):
        return reverse("episode-list", kwargs={"parent_slug": self.object.parent.slug})


@attach
class EpisodeListView(PageListView):
    model = Episode
    filterset_class = filters.EpisodeFilters
    parent_model = Program
    attach_to_value = StaticPage.Target.EPISODES


@attach
class PodcastListView(EpisodeListView):
    attach_to_value = StaticPage.Target.PODCASTS
    queryset = Episode.objects.published().with_podcasts().order_by("-pub_date")


class EpisodeUpdateView(UserPassesTestMixin, VueFormDataMixin, PageUpdateView):
    model = Episode
    form_class = forms.EpisodeForm
    template_name = "aircox/episode_form.html"

    def can_edit(self, obj):
        return self.test_func()

    def test_func(self):
        obj = self.get_object()
        return permissions.program.can(self.request.user, "update", obj)

    def get_tracklist_queryset(self, episode):
        return Track.objects.filter(episode=episode).order_by("position")

    def get_tracklist_formset(self, episode, **kwargs):
        kwargs.update(
            {
                "prefix": "tracks",
                "queryset": self.get_tracklist_queryset(episode),
                "initial": [
                    {
                        "episode": episode.id,
                    }
                ],
            }
        )
        return forms.TrackFormSet(**kwargs)

    def get_soundlist_queryset(self, episode):
        return episode.episodesound_set.all().select_related("sound").order_by("position")

    def get_soundlist_formset(self, episode, **kwargs):
        kwargs.update(
            {
                "prefix": "sounds",
                "queryset": self.get_soundlist_queryset(episode),
                "initial": [
                    {
                        "episode": episode.id,
                    }
                ],
            }
        )
        return forms.EpisodeSoundFormSet(**kwargs)

    def get_sound_form(self, episode, **kwargs):
        kwargs.update(
            {
                "initial": {
                    "program": episode.parent_id,
                    "name": episode.title,
                    "is_public": True,
                },
            }
        )
        return forms.SoundCreateForm(**kwargs)

    def get_context_data(self, **kwargs):
        forms = (
            ("soundlist_formset", self.get_soundlist_formset),
            ("tracklist_formset", self.get_tracklist_formset),
            ("sound_form", self.get_sound_form),
        )
        for key, func in forms:
            if key not in kwargs:
                kwargs[key] = func(self.object)

        for key in ("soundlist_formset", "tracklist_formset"):
            formset = kwargs[key]
            kwargs[f"{key}_data"] = self.get_formset_data(formset, {"episode": self.object.id})
        return super().get_context_data(**kwargs)

    def post(self, request, *args, **kwargs):
        resp = super().post(request, *args, **kwargs)

        formsets = {
            "soundlist_formset": self.get_soundlist_formset(self.object, data=request.POST),
            "tracklist_formset": self.get_tracklist_formset(self.object, data=request.POST),
        }
        invalid = False
        for formset in formsets.values():
            if not formset.is_valid():
                invalid = True
            else:
                formset.save()
        if invalid:
            return self.get(request, **formsets)
        return resp


class EpisodeCreateView(UserPassesTestMixin, View):
    def get(self, request, **kwargs):
        program = self.get_object()
        episode = Episode.objects.create(program=program, title="%s (%s)" % (program.title, _("draft")))
        return HttpResponseRedirect(reverse("episode-edit", kwargs={"pk": episode.pk}))

    def test_func(self):
        program = self.get_object()
        return permissions.program.can(self.request.user, "update", program)

    def get_object(self):
        return get_object_or_404(Program, pk=self.kwargs["pk"])
