from collective.workspace.interfaces import IWorkspace
from plone import api
from plone.app.testing import login
from plone.app.testing import logout
from plone.app.testing.interfaces import SITE_OWNER_NAME
from plone.app.testing.interfaces import SITE_OWNER_PASSWORD
from plone.testing import zope as zope_testing
from plone.testing.zope import Browser
from ploneintranet import api as pi_api
from ploneintranet.search.solr.interfaces import IMaintenance
from ploneintranet.workspace.testing import PLONEINTRANET_WORKSPACE_FUNCTIONAL_TESTING
from ploneintranet.workspace.testing import PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING
from ploneintranet.workspace.testing import (
    PLONEINTRANET_WORKSPACE_WORKFLOW_INTEGRATION_TESTING,
)
from Products.CMFCore.indexing import processQueue
from zope.component import getUtility

import unittest
import zope.deferredimport

zope.deferredimport.initialize()

zope.deferredimport.deprecated(
    "Use from ploneintranet.testing import temporary_registry_record instead",
    temporary_registry_record="ploneintranet.testing:temporary_registry_record",
)


class BaseTestCase(unittest.TestCase):

    layer = PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING

    def setUp(self):
        self.app = self.layer["app"]
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]
        pi_api.events.disable_previews()
        self.workspace_container = self.portal.workspaces
        self.portal_workflow = api.portal.get_tool("portal_workflow")
        # Start each test with a fresh cache
        if hasattr(self.portal.acl_users, "_memcachedcounter"):
            delattr(self.portal.acl_users, "_memcachedcounter")

    def solr_commit(self):
        """On integration tests we need to commit on solr before searching"""
        processQueue()
        getUtility(IMaintenance).connection.commit()

    def cleanup_request_annotations(self):
        """Invalidate the cache of the workspace"""
        try:
            self.request.__annotations__.clear()
        except AttributeError:
            pass

    def login(self, username):
        """
        helper method to login as specific user

        Before logging in cleanup the request annotations in case

        - some pas plugins is storing there informations about the current user
        - some memoized methods needs to be cleaned up

        :param username: the username of the user to add to the group
        :type username: str
        :rtype: None

        """
        login(self.portal, username)
        self.cleanup_request_annotations()

    def logout(self):
        """
        helper method to avoid importing the p.a.testing logout method
        """
        logout()

    def login_as_portal_owner(self):
        """
        helper method to login as site admin
        """
        zope_testing.login(self.app["acl_users"], SITE_OWNER_NAME)

    def add_user_to_workspace(self, username, workspace, groups=None):
        """
        helper method which adds a user to team and then clears the cache

        :param username: the username of the user to add to the group
        :type username: str
        :param workspace: the workspace to add this user
        :type workspace: ploneintranet.workspace.workspacefolder
        :param groups: the groups to which this user should be added
        :type groups: set
        :rtype: None

        """
        IWorkspace(workspace).add_to_team(username, **{"groups": groups})


class FunctionalBaseTestCase(BaseTestCase):

    layer = PLONEINTRANET_WORKSPACE_FUNCTIONAL_TESTING

    def setUp(self):
        super().setUp()
        self.browser = Browser(self.app)
        self.browser.handleErrors = False

    def browser_login_as_site_administrator(self):
        self.browser.open(self.portal.absolute_url() + "/login")
        self.browser.getControl(name="__ac_name").value = SITE_OWNER_NAME
        self.browser.getControl(name="__ac_password").value = SITE_OWNER_PASSWORD
        self.browser.getControl(name="buttons.login").click()


class WorkflowBaseTestCase(BaseTestCase):

    layer = PLONEINTRANET_WORKSPACE_WORKFLOW_INTEGRATION_TESTING

    object_to_check = None  # needs to be set by subclass in setUp

    def setUp(self):
        super().setUp()
        self.workspace_folder = self.portal.workspaces["demo-workspace"]
        self.event = self.workspace_folder["owner-event"]

    def _check_permission_for(self, username, permission):
        permissions = api.user.get_permissions(
            username=username, obj=self.object_to_check
        )
        return permissions[permission]

    def admin_permissions(self, permission):
        return self._check_permission_for("wsadmin", permission)

    def editor_permissions(self, permission):
        return self._check_permission_for("wseditor", permission)

    def member_permissions(self, permission):
        return self._check_permission_for("wsmember", permission)

    def intranet_permissions(self, permission):
        return self._check_permission_for("intranet", permission)

    def extranet_permissions(self, permission):
        return self._check_permission_for("extranet", permission)

    def anon_permissions(self, permission):
        self.logout()
        return self._check_permission_for(None, permission)
