"""HTMX mixins for views. Canonical definitions for partial rendering and triggers."""

from typing import Any

from django.template import TemplateDoesNotExist
from django.template.loader import select_template
from django.views.generic.edit import FormMixin
from django.views.generic.list import MultipleObjectMixin


class HTMXFilterableMixin(MultipleObjectMixin):
    """Enhance list views to return partial templates for HTMX requests."""

    filter_class: type[Any] | None = None
    htmx_partial_suffix = "_partial.html"

    def get_queryset(self):
        """Apply the filter class to the queryset if defined."""
        qs = super().get_queryset()
        filter_cls = self.filter_class
        if filter_cls:
            # pylint: disable=not-callable
            self.filterset = filter_cls(self.request.GET, queryset=qs)
            return self.filterset.qs
        return qs

    def get_template_names(self):
        """Return partial template if HTMX request, otherwise default templates."""
        names = super().get_template_names()
        if self.request.headers.get("HX-Request") == "true":
            partials = [t.replace(".html", self.htmx_partial_suffix) for t in names]
            try:
                select_template(partials)
                return partials
            except TemplateDoesNotExist:
                return names
        return names

    def get_context_data(self, **kwargs):
        """Add the filterset to the context."""
        ctx = super().get_context_data(**kwargs)
        if hasattr(self, "filterset"):
            ctx["filter"] = self.filterset
        return ctx


class HTMXFormMixin(FormMixin):
    """FormMixin that returns partials and field-level errors for HTMX requests."""

    htmx_success_trigger: str | None = None

    def form_invalid(self, form):
        """Return partial with errors on invalid form submission via HTMX."""
        if self.request.headers.get("HX-Request") == "true":
            return self.render_to_response(self.get_context_data(form=form))
        return super().form_invalid(form)

    def form_valid(self, form):
        """Add HX-Trigger header on successful form submission via HTMX."""
        res = super().form_valid(form)
        if self.request.headers.get("HX-Request") == "true" and self.htmx_success_trigger:
            res["HX-Trigger"] = self.htmx_success_trigger
        return res


class HTMXInlineEditMixin(FormMixin):
    """
    Support simple inline edit flows.

    GET returns form partial, POST returns updated fragment.
    """


class HTMXPaginationMixin:
    """
    Pagination helper.

    Supports hx-trigger based infinite scroll or standard pagination.
    """

    page_size = 20

    def get_paginate_by(self, _queryset):
        """Return the number of items to paginate by."""
        return getattr(self, "paginate_by", self.page_size)


class HTMXModalMixin(HTMXFormMixin):
    """Mixin to help render forms inside modals and send close triggers on success."""

    modal_close_trigger = "modal:close"

    def form_valid(self, form):
        """Send close trigger on successful form submission via HTMX."""
        res = super().form_valid(form)
        if self.request.headers.get("HX-Request") == "true":
            res["HX-Trigger"] = self.modal_close_trigger
        return res
