from django.utils.functional import cached_property
from django.views.generic import UpdateView
from rules.contrib.views import AutoPermissionRequiredMixin, PermissionRequiredMixin

from servala.core.models import Organization


class HtmxViewMixin:
    fragments = []

    @cached_property
    def is_htmx(self):
        return self.request.headers.get("HX-Request")

    def _get_fragment(self):
        if self.request.method == "POST":
            fragment = self.request.POST.get("fragment")
        else:
            fragment = self.request.GET.get("fragment")
        if fragment and fragment in self.fragments:
            return fragment

    def get_template_names(self):
        template_names = super().get_template_names()
        if self.is_htmx and (fragment := self._get_fragment()):
            return [f"{template_names[0]}#{fragment}"]
        return template_names


class HtmxUpdateView(AutoPermissionRequiredMixin, HtmxViewMixin, UpdateView):

    @property
    def permission_type(self):
        if self.request.method == "POST" or getattr(
            self, "_test_write_permission", False
        ):
            return "change"
        return "view"

    def has_change_permission(self):
        self._test_write_permission = True
        permission = self.get_permission_required()[0]
        self._test_write_permission = False
        return self.request.user.has_perm(permission, self.get_permission_object())

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

    def get_form_kwargs(self):
        result = super().get_form_kwargs()
        if self.is_htmx:
            data = (
                self.request.POST if self.request.method == "POST" else self.request.GET
            )
            result["single_field"] = data.get("hx-single-field")
        return result

    def form_valid(self, form):
        result = super().form_valid(form)
        if self.is_htmx and self._get_fragment():
            return self.get(self.request, *self.args, **self.kwargs)
        return result


class OrganizationViewMixin(PermissionRequiredMixin):
    model = Organization
    context_object_name = "organization"
    permission_required = "core.view_organization"

    @cached_property
    def organization(self):
        return self.request.organization

    def get_object(self):
        if self.model == Organization:
            return self.organization
        return super().get_object()

    @cached_property
    def object(self):
        return self.get_object()

    def get_permission_object(self):
        return self.organization

    def has_organization_permission(self):
        return self.request.user.has_perm("core.view_organization", self.organization)

    def has_permission(self):
        return self.has_organization_permission() and super().has_permission()
