from django.contrib.auth.models import Group
from django.urls import re_path
from django.utils.translation import gettext as _

from wagtail.admin.views import generic, mixins
from wagtail.admin.viewsets.model import ModelViewSet
from wagtail.core import hooks
from wagtail.users.forms import GroupForm, GroupPagePermissionFormSet
from wagtail.users.views.users import index

_permission_panel_classes = None


def get_permission_panel_classes():
    global _permission_panel_classes
    if _permission_panel_classes is None:
        _permission_panel_classes = [GroupPagePermissionFormSet]
        for fn in hooks.get_hooks('register_group_permission_panel'):
            _permission_panel_classes.append(fn())

    return _permission_panel_classes


class PermissionPanelFormsMixin:
    def get_permission_panel_form_kwargs(self, cls):
        kwargs = {}

        if self.request.method in ('POST', 'PUT'):
            kwargs.update({
                'data': self.request.POST,
                'files': self.request.FILES,
            })

        if hasattr(self, 'object'):
            kwargs.update({'instance': self.object})

        return kwargs

    def get_permission_panel_forms(self):
        return [
            cls(**self.get_permission_panel_form_kwargs(cls))
            for cls in get_permission_panel_classes()
        ]

    def get_context_data(self, **kwargs):
        if 'permission_panels' not in kwargs:
            kwargs['permission_panels'] = self.get_permission_panel_forms()

        return super().get_context_data(**kwargs)


class IndexView(mixins.SearchableListMixin, generic.IndexView):
    page_title = _("Groups")
    add_item_label = _("Add a group")
    search_box_placeholder = _("Search groups")
    search_fields = ['name']
    context_object_name = 'groups'
    paginate_by = 20
    page_kwarg = 'p'
    ordering = ['name']

    def get_template_names(self):
        if self.request.is_ajax():
            return ['wagtailusers/groups/results.html']
        else:
            return ['wagtailusers/groups/index.html']


class CreateView(PermissionPanelFormsMixin, generic.CreateView):
    page_title = _("Add group")
    success_message = _("Group '{0}' created.")
    template_name = 'wagtailusers/groups/create.html'

    def post(self, request, *args, **kwargs):
        """
        Handle POST requests: instantiate a form instance with the passed
        POST variables and then check if it's valid.
        """
        # Create an object now so that the permission panel forms have something to link them against
        self.object = Group()

        form = self.get_form()
        permission_panels = self.get_permission_panel_forms()
        if form.is_valid() and all(panel.is_valid() for panel in permission_panels):
            response = self.form_valid(form)

            for panel in permission_panels:
                panel.save()

            return response
        else:
            return self.form_invalid(form)

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

        # add a 'form_media' variable for the collected js/css media from the form and all formsets
        form_media = context['form'].media
        for panel in context['permission_panels']:
            form_media += panel.media
        context['form_media'] = form_media

        return context


class EditView(PermissionPanelFormsMixin, generic.EditView):
    success_message = _("Group '{0}' updated.")
    error_message = _("The group could not be saved due to errors.")
    delete_item_label = _("Delete group")
    context_object_name = 'group'
    template_name = 'wagtailusers/groups/edit.html'

    def post(self, request, *args, **kwargs):
        """
        Handle POST requests: instantiate a form instance with the passed
        POST variables and then check if it's valid.
        """
        self.object = self.get_object()

        form = self.get_form()
        permission_panels = self.get_permission_panel_forms()
        if form.is_valid() and all(panel.is_valid() for panel in permission_panels):
            response = self.form_valid(form)

            for panel in permission_panels:
                panel.save()

            return response
        else:
            return self.form_invalid(form)

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

        # add a 'form_media' variable for the collected js/css media from the form and all formsets
        form_media = context['form'].media
        for panel in context['permission_panels']:
            form_media += panel.media
        context['form_media'] = form_media

        return context


class DeleteView(generic.DeleteView):
    success_message = _("Group '{0}' deleted.")
    page_title = _("Delete group")
    confirmation_message = _("Are you sure you want to delete this group?")
    template_name = 'wagtailusers/groups/confirm_delete.html'


class GroupViewSet(ModelViewSet):
    icon = 'group'
    model = Group

    index_view_class = IndexView
    add_view_class = CreateView
    edit_view_class = EditView
    delete_view_class = DeleteView

    @property
    def users_view(self):
        return index

    def get_form_class(self, for_update=False):
        return GroupForm

    def get_urlpatterns(self):
        return super().get_urlpatterns() + [
            re_path(r'(\d+)/users/$', self.users_view, name='users'),
        ]
