from plone import api
from plone.memoize.view import memoize
from ploneintranet import api as pi_api
from ploneintranet.core import _
from ploneintranet.layout.browser.base import BasePanel
from ploneintranet.userprofile.behaviors.maintainer_group import (
    IMaintainerGroupListSupport,
)
from ploneintranet.workspace.basecontent.utils import dexterity_update
from ploneintranet.workspace.browser.add_content import AddBase

import json


class MaintainerGroupListMixin:
    """
    Mixin for the MaintainerGroupList panel.
    """

    picker_view_name = "group_picker.json"

    def query_groups(self, group_ids):
        return pi_api.workgroup.get_groups(
            exact_getGroupId=list(group_ids),
            full_objects=False,
        )

    @property
    def maintainer_group_list_data_pat_autosuggest(self):
        """Return the parameters that should be used for the autosuggest list"""
        portal = api.portal.get()
        prefill_json = self.prefill_for_maintainer_group_list
        selection_classes = self.selection_classes_for_maintainer_group_list
        return "; ".join(
            (
                f"selection-classes: {selection_classes}",
                f"prefill-json: {prefill_json}",
                "allow-new-words: false",
                "ajax-search-index: text",
                f"ajax-url: {portal.absolute_url()}/@@{self.picker_view_name}",
            )
        )


class PanelCreateLibrarySection(AddBase, MaintainerGroupListMixin):
    """Add a library section"""

    _form_data_pat_inject_parts = (
        "#portal-content",
        "#global-statusmessage; loading-class: ''",
    )

    portal_type = "ploneintranet.library.section"
    title = _("label_create_library_section", "Create library section")

    @property
    def template(self):
        return self.index

    def show_maintainer_group_list_field(self):
        """The field maintainer_group_list is only shown
        if the behavior quaive.maintainer_group_list is available for
        the portal_type we want to add
        """
        # XXX Skip this for the time being
        pt = api.portal.get_tool("portal_types")
        return "quaive.maintainer_group_list" in pt[self.portal_type].behaviors

    @property
    @memoize
    def default_maintainer_group_ids(self):
        if IMaintainerGroupListSupport.providedBy(self.context):
            return self.context.maintainer_group_list or set()
        return set()

    @property
    def selection_classes_for_maintainer_group_list(self) -> str:
        """Return the jsonified representation of a dict that looks like:

        {"Group title 1": ["disabled"], ...}

        Used to gray out the pills in the autosuggest widget
        """
        if not self.default_maintainer_group_ids:
            return "{}"
        return json.dumps(
            {
                group.Title: ["disabled"]
                for group in self.query_groups(self.default_maintainer_group_ids)
            }
        )

    @property
    def prefill_for_maintainer_group_list(self) -> str:
        """Returns the jsonified representation of a dict that looks like:

        {"Group id 1": "Group title 1", ...}

        Used to display the values currently stored in the maintainer_group_list
        """
        group_ids = self.default_maintainer_group_ids
        if not group_ids:
            return "[]"

        groups = self.query_groups(group_ids)

        # Sort the groups putting the inherited one first
        return json.dumps({group.getGroupId: group.Title for group in groups})

    def create(self, container=None):
        if self.show_maintainer_group_list_field():
            # We need to preprocess the form data to make sure to
            # filter out the group ids that come from the parent containers but keep
            # the one that might have been already defined here
            banned_group_ids = self.default_maintainer_group_ids
            submitted_group_ids = set(
                self.request.form["maintainer_group_list"].split(",")
            )
            self.request.form["maintainer_group_list"] = ",".join(
                submitted_group_ids - banned_group_ids
            )
        return super().create(container=container)


class PanelCreateLibraryFolder(PanelCreateLibrarySection):
    """Add a library folder"""

    portal_type = "ploneintranet.library.folder"


class PanelEditLibrarySection(BasePanel, MaintainerGroupListMixin):
    """
    Edit the library section security and metadata
    """

    title = _("label_edit_library_section", "Edit library section")
    _form_data_pat_inject_parts = ("#portal-content-pane",)

    @property
    @memoize
    def inherited_maintainer_group_list(self) -> set:
        """Gather the group ids stored in the parent containers.
        They will be displayed as greyed out in the autosuggest widget.
        """
        groups = set()
        for obj in self.context.aq_parent.aq_chain:
            if IMaintainerGroupListSupport.providedBy(obj):
                groups.update(obj.maintainer_group_list)
        return groups

    @property
    def prefill_for_maintainer_group_list(self) -> str:
        """Returns the jsonified representation of a dict that looks like:

        {"Group id 1": "Group title 1", ...}

        Used to display the values currently stored in the maintainer_group_list
        """
        group_ids = (
            self.inherited_maintainer_group_list | self.context.maintainer_group_list
        )
        if not group_ids:
            return "[]"

        groups = self.query_groups(group_ids)

        # Sort the groups putting the inherited one first
        groups = sorted(
            groups,
            key=(
                lambda group: group.getGroupId
                not in self.inherited_maintainer_group_list
            ),
        )
        return json.dumps({group.getGroupId: group.Title for group in groups})

    @property
    def selection_classes_for_maintainer_group_list(self) -> str:
        """Return the jsonified representation of a dict that looks like:

        {"Group title 1": ["disabled"], ...}

        Used to gray out the pills in the autosuggest widget
        """
        group_ids = (
            self.inherited_maintainer_group_list - self.context.maintainer_group_list
        )
        if not group_ids:
            return "{}"
        return json.dumps(
            {group.Title: ["disabled"] for group in self.query_groups(group_ids)}
        )

    @property
    def maintainer_group_list_data_pat_autosuggest(self):
        """Return the parameters that should be used for the autosuggest list"""
        portal = api.portal.get()
        prefill_json = self.prefill_for_maintainer_group_list
        selection_classes = self.selection_classes_for_maintainer_group_list
        return "; ".join(
            (
                f"selection-classes: {selection_classes}",
                f"prefill-json: {prefill_json}",
                "allow-new-words: false",
                "ajax-search-index: text",
                f"ajax-url: {portal.absolute_url()}/@@{self.picker_view_name}",
            )
        )

    def show_maintainer_group_list_field(self):
        """The field maintainer_group_list is only shown
        if the IMaintainerGroupListSupport is provided by the object through the
        behavior quaive.maintainer_group_list
        """
        return IMaintainerGroupListSupport.providedBy(self.context)

    def execute_on_post(self):
        if self.show_maintainer_group_list_field():
            # We need to preprocess the form data to make sure to
            # filter out the group ids that come from the parent containers but keep
            # the one that might have been already defined here
            banned_group_ids = (
                self.inherited_maintainer_group_list
                - self.context.maintainer_group_list
            )
            submitted_group_ids = set(
                self.request.form["maintainer_group_list"].split(",")
            )
            self.request.form["maintainer_group_list"] = ",".join(
                submitted_group_ids - banned_group_ids
            )
        dexterity_update(self.context, self.request)
        return self.request.response.redirect(self.context.absolute_url())
