from django.http import Http404, HttpResponse
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.views.generic.edit import UpdateView
from honeypot.decorators import check_honeypot

from ..filters import PageFilters
from ..forms import CommentForm
from ..models import Comment
from ..utils import Redirect
from .base import BaseView
from .mixins import AttachedToMixin, FiltersMixin, ParentMixin

__all__ = [
    "BasePageListView",
    "BasePageDetailView",
    "PageDetailView",
    "PageListView",
]


class BasePageListView(AttachedToMixin, ParentMixin, BaseView, ListView):
    """Base view class for BasePage list."""

    template_name = "aircox/basepage_list.html"
    item_template_name = "aircox/widgets/page_item.html"
    has_sidebar = True

    paginate_by = 30
    has_headline = True

    def get(self, *args, **kwargs):
        return super().get(*args, **kwargs)

    def get_queryset(self):
        return super().get_queryset().select_subclasses().published().select_related("cover")

    def get_context_data(self, **kwargs):
        kwargs.setdefault("item_template_name", self.item_template_name)
        kwargs.setdefault("has_headline", self.has_headline)
        return super().get_context_data(**kwargs)


class BasePageDetailView(BaseView, DetailView):
    """Base view class for BasePage."""

    template_name = "aircox/basepage_detail.html"
    context_object_name = "page"
    has_filters = False

    def get_queryset(self):
        return super().get_queryset().select_related("cover")

    # This should not exists: it allows mapping not published pages
    # or it should be only used for trashed pages.
    def not_published_redirect(self, page):
        """When a page is not published, redirect to the returned url instead
        of an HTTP 404 code."""
        return None

    def get_object(self):
        if getattr(self, "object", None):
            return self.object

        obj = super().get_object()
        if not obj.is_published:
            redirect_url = self.not_published_redirect(obj)
            if redirect_url:
                raise Redirect(redirect_url)
            raise Http404("%s not found" % self.model._meta.verbose_name)
        return obj

    def get_page(self):
        return self.object


class PageListView(FiltersMixin, BasePageListView):
    """Page list view."""

    filterset_class = PageFilters
    template_name = None
    has_filters = True
    categories = None
    filters = None

    def get_template_names(self):
        return super().get_template_names() + ["aircox/page_list.html"]

    def get_filterset(self, data, query):
        # FIXME: not the most efficient, cause join then split (django filters)
        data["category__id__in"] = ",".join(data.getlist("category__id__in"))
        return super().get_filterset(data, query)

    def get_queryset(self):
        qs = super().get_queryset().select_related("category").order_by("-pub_date")
        return qs

    def get_context_data(self, **kwargs):
        kwargs["categories"] = (
            self.model.objects.published()
            .filter(category__isnull=False)
            .values_list("category__title", "category__id")
            .distinct()
        )
        return super().get_context_data(**kwargs)


class PageDetailView(BasePageDetailView):
    """Base view class for pages."""

    template_name = None
    context_object_name = "page"
    has_filters = False

    def get_template_names(self):
        return super().get_template_names() + ["aircox/page_detail.html"]

    def get_queryset(self):
        return super().get_queryset().select_related("category")

    def get_context_data(self, **kwargs):
        if self.object.allow_comments and "comment_form" not in kwargs:
            kwargs["comment_form"] = CommentForm()
        kwargs["comments"] = Comment.objects.filter(page=self.object).order_by("-date")
        return super().get_context_data(**kwargs)

    @classmethod
    def as_view(cls, *args, **kwargs):
        view = super(PageDetailView, cls).as_view(*args, **kwargs)
        return check_honeypot(view, field_name="website")

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        if not self.object.allow_comments:
            return HttpResponse(_("comments are not allowed"), status=503)

        form = CommentForm(request.POST)
        comment = form.save(commit=False)
        comment.page = self.object
        comment.save()
        return self.get(request, *args, **kwargs)


class PageUpdateView(BaseView, UpdateView):
    context_object_name = "page"

    def get_page(self):
        return self.object
