from plone import api
from plone.memoize.view import memoize
from plone.memoize.view import memoize_contextless
from ploneintranet.userprofile.subscribers import on_membrane_principal_modified
from Products.Five import BrowserView
from Products.PlonePAS.interfaces.plugins import ILocalRolesPlugin


class View(BrowserView):
    """Context is a team membership object"""

    @property
    @memoize
    def admins_groupid(self):
        return "Admins:%s" % self.context.workspace.context.UID()

    @property
    def current_owner_id(self):
        """Return the currect workspace owner id"""
        return self.context.workspace.context.getOwnerTuple()[1]

    @memoize_contextless
    def resolve_principal(self, principalid):
        return api.user.get(principalid) or api.group.get(principalid)

    @memoize
    def is_admin(self, principal):
        """Check if principal is an Admin"""
        if isinstance(principal, str):
            principal = self.resolve_principal(principal)
        if not principal:
            return False

        group_ids = []
        if getattr(principal, "getGroupIds", False):
            # in case of principal == PIUser
            group_ids = principal.getGroupIds()
        elif getattr(principal, "getGroups", False):
            # in case of principal == MemberData
            group_ids = principal.getGroups()
        return self.admins_groupid in group_ids

    @property
    @memoize_contextless
    def local_role_plugins(self):
        pas = api.portal.get_tool("acl_users")
        return pas.plugins.listPlugins(ILocalRolesPlugin)

    @memoize_contextless
    def pick_userid_from_principalid(self, principalid):
        """Given a principalid try to get the principal.
        If principal is a user, return it,
        if principal is a group return the first user found in the group
        or in a subgroup
        """
        user = api.user.get(principalid)
        if user:
            try:
                return user.getUserId()
            except AttributeError:
                return user.getId()

        group = self.resolve_principal(principalid)
        if not group:
            return

        for memberid in group.getMemberIds():
            user = self.pick_userid_from_principalid(memberid)
            if user:
                return user

    @property
    @memoize
    def new_owner_id(self):
        """Try to pick the best owner id for the workspace"""
        me = api.user.get_current()
        try:
            me_id = me.getUserId()
        except AttributeError:
            me_id = me.getId()
        # FIXME This is necessary because of:
        # https://github.com/quaive/ploneintranet/issues/2366
        me = api.user.get(me_id)
        # Check if current user is an admin
        if self.is_admin(me):
            return me_id
        # If not try to pick a user between the admins
        group = self.resolve_principal(self.admins_groupid)
        if not group:
            return me_id
        # Sort ids in a way that the current user is the first one
        for principalid in group.getMemberIds():
            userid = self.pick_userid_from_principalid(principalid)
            if userid:
                return userid
        # Fallback: no suitable Admins found. But the current user still had
        # the necessary permissions to remove the former Owner. Therefore
        # grant Ownership.
        return me_id

    def _is_local_owner_of(self, obj):
        """Check if current user is an owner in this context"""
        for _, lrmanager in self.local_role_plugins:
            for adapter in lrmanager._getAdapters(obj):
                if "Owner" in adapter.getRoles(self.context.user):
                    return True
        return False

    def _purge_owner(self, obj, force_reindex=False, force_change=False):
        if force_change or obj.getOwnerTuple()[1] == self.context.user:
            new_owner_id = self.new_owner_id
            if new_owner_id == self.context.user:
                # Current owner is already the best choice
                return
            obj.changeOwnership(self.resolve_principal(new_owner_id).getUser())

        if self._is_local_owner_of(obj):
            obj.manage_delLocalRoles([self.context.user])
            force_reindex = True

        if force_reindex:
            obj.reindexObject()

        if obj.meta_type not in ["Dexterity Container"]:
            return

        for idx, sub_obj in obj.ZopeFind(obj, search_sub=0):
            if sub_obj.meta_type in ["Dexterity Item", "Dexterity Container"]:
                # If the Owner role was found on the current container,
                # all sub-items need to be reindexed too, because of role
                # inheritance. Even though direct access will have been
                # taken away by removing the local role, the sub-items of
                # the container might still appear in search results,
                # including previews.
                self._purge_owner(sub_obj, force_reindex=force_reindex)

    def maybe_purge_owner(self):
        """Verify that the current owner is an admin, if not change it"""
        # First of all fix the groups plugin
        on_membrane_principal_modified(self.context.workspace.context)

        # Then check what is the best choice here
        if self.is_admin(self.current_owner_id):
            # The current owner is an admin which is good
            # and does not require any action
            return

        # Otherwise we want some other admin to own the workspace
        self._purge_owner(self.context.workspace.context, force_change=True)
