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

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

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


class BasePageMixin:
    category = None

    def get_queryset(self):
        qs = super().get_queryset().select_subclasses().select_related("cover")
        if self.request.user.is_authenticated:
            return qs
        return qs.published()

    def get_category(self, page, **kwargs):
        if page:
            if getattr(page, "category_id", None):
                return page.category
            if page.parent_id:
                return self.get_category(page.parent_subclass)
        if slug := self.kwargs.get("category_slug"):
            return Category.objects.get(slug=slug)
        return None

    def get_context_data(self, *args, **kwargs):
        kwargs.setdefault("category", self.category)
        return super().get_context_data(*args, **kwargs)


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

    template_name = "aircox/basepage_list.html"

    paginate_by = 30
    has_headline = True

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

    def get(self, *args, **kwargs):
        self.category = self.get_category(self.parent)
        return super().get(*args, **kwargs)

    def get_queryset(self):
        query = super().get_queryset()
        if self.category:
            query = query.filter(category=self.category)
        return query

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

        parent = context.get("parent")
        if not context.get("page"):
            if not context.get("title"):
                model = self.model._meta.verbose_name_plural
                title = _("{model}")
                context["title"] = title.format(model=model, parent=parent)

            if not context.get("cover") and parent and parent.cover:
                context["cover"] = parent.cover.url

        return context


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

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

    def get_context_data(self, **kwargs):
        if self.object.cover:
            kwargs.setdefault("cover", self.object.cover.url)
        if self.object.title:
            kwargs.setdefault("title", self.object.display_title)
        return super().get_context_data(**kwargs)

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

        obj = super().get_object()
        self.category = self.get_category(obj)
        return obj

    def get_page(self):
        return self.object


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

    filterset_class = PageFilters
    template_name = None
    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")
        cat_ids = self.model.objects.published().values_list("category_id", flat=True)
        self.categories = Category.objects.filter(id__in=cat_ids)
        return qs

    @classmethod
    def get_secondary_nav(cls):
        cat_ids = cls.model.objects.published().values_list("category_id", flat=True)
        categories = Category.objects.filter(id__in=cat_ids)
        return tuple(
            (category.title, reverse(cls.model.list_url_name, kwargs={"category_slug": category.slug}))
            for category in categories
        )

    def get_context_data(self, **kwargs):
        kwargs["categories"] = self.categories
        return super().get_context_data(**kwargs)


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

    template_name = None
    context_object_name = "page"

    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 "comment_form" not in kwargs:
            kwargs["comment_form"] = self.get_comment_form()
        kwargs["comments"] = Comment.objects.filter(page=self.object).order_by("-date")

        if self.object.parent_subclass:
            kwargs["parent"] = self.object.parent_subclass

        if "related_objects" not in kwargs:
            related = self.get_related_queryset()
            if related:
                related = related[: self.related_count]
            kwargs["related_objects"] = related
        return super().get_context_data(**kwargs)

    def get_comment_form(self):
        if self.object.allow_comments:
            return CommentForm()
        return None

    @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"
    template_name = "aircox/page_form.html"

    def get_page(self):
        return self.object

    def get_success_url(self):
        return self.request.path

    def get_comment_form(self):
        return None
