from collective.workspace.interfaces import IWorkspace
from plone import api
from plone.app.testing import applyProfile
from plone.app.testing import MOCK_MAILHOST_FIXTURE
from plone.app.testing import PloneSandboxLayer
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.app.testing import TEST_USER_PASSWORD
from plone.testing import zope as zope_testing
from plone.testing.zope import WSGI_SERVER_FIXTURE
from ploneintranet import api as pi_api
from ploneintranet.search.interfaces import IPloneintranetSearchLayer
from ploneintranet.search.solr.testing import load_solr_zcml
from ploneintranet.search.solr.testing import SOLR_FIXTURE
from ploneintranet.search.solr.testing import SolrFunctionalTesting
from ploneintranet.search.solr.testing import SolrIntegrationTesting
from ploneintranet.userprofile.testing import PLONEINTRANET_USERPROFILE_FIXTURE
from zope.component import getUtility
from zope.event import notify
from zope.interface import alsoProvides
from zope.lifecycleevent import ObjectModifiedEvent

import ploneintranet.activitystream
import ploneintranet.invitations
import ploneintranet.layout
import ploneintranet.microblog
import ploneintranet.microblog.statuscontainer
import ploneintranet.network
import ploneintranet.theme
import ploneintranet.userprofile
import ploneintranet.workspace
import quaive.resources.ploneintranet


class PloneintranetworkspaceLayer(PloneSandboxLayer):

    defaultBases = (SOLR_FIXTURE, PLONEINTRANET_USERPROFILE_FIXTURE)

    def purge_solr(self):
        from ploneintranet.search.solr.interfaces import IMaintenance

        getUtility(IMaintenance).purge()

    def solr_sync(self, portal):
        """Sync the portal content in to Solr"""
        with api.env.adopt_user("admin"):
            request = portal.REQUEST
            alsoProvides(request, IPloneintranetSearchLayer)
            view = api.content.get_view("solr-maintenance", portal, request)
            view.sync(close_connection=True)

    def setUpZope(self, app, configurationContext):
        # Load ZCML
        self.loadZCML(package=ploneintranet.workspace)
        self.loadZCML(package=quaive.resources.ploneintranet)
        self.loadZCML(package=ploneintranet.search.solr)
        load_solr_zcml()
        zope_testing.installProduct(app, "collective.workspace")

    def tearDownZope(self, app):
        zope_testing.uninstallProduct(app, "collective.workspace")

    def createPloneContents(self, portal):
        """Creates the contents for this Plone test layer"""
        with api.env.adopt_user("admin"):
            api.content.create(
                portal.workspaces,
                "ploneintranet.workspace.workspacefolder",
                "demo-workspace",
                title="Demo Workspace",
            )
            api.user.create(
                email="demo@example.org", username="demo", password=TEST_USER_PASSWORD
            )

    def setUpPloneSite(self, portal):
        applyProfile(portal, "ploneintranet.workspace:default")
        applyProfile(portal, "ploneintranet.bookmarks:default")
        applyProfile(portal, "quaive.resources.ploneintranet:default")
        self.purge_solr()
        setRoles(portal, TEST_USER_ID, ["Manager"])
        portal.acl_users.userFolderAddUser("admin", "secret", ["Manager"], [])
        self.createPloneContents(portal)
        self.solr_sync(portal)
        SOLR_FIXTURE._solr_snapshot()


class PloneintranetworkspaceGroupspaceLayer(PloneintranetworkspaceLayer):
    def createPloneContents(self, portal):
        super().createPloneContents(portal)

        with api.env.adopt_user("admin"):
            pi_api.userprofile.create(
                username="johndoe", email="johndoe@doe.com", approve=True
            )
            pi_api.userprofile.create(
                username="janeschmo", email="janeschmo@doe.com", approve=True
            )

            workspace_a = api.content.create(
                portal.workspaces,
                "ploneintranet.workspace.workspacefolder",
                "workspace-a",
                title="Workspace A",
            )
            workspace_a.visible_to_intranet_users = True
            IWorkspace(workspace_a).add_to_team("johndoe", groups=None)

            # Add a second and third workspace, without participants
            workspace_b = api.content.create(
                portal.workspaces,
                "ploneintranet.workspace.workspacefolder",
                "workspace-b",
                title="Workspace 𝔅",
            )
            workspace_b.visible_to_intranet_users = True

            api.content.create(
                portal.workspaces,
                "ploneintranet.workspace.workspacefolder",
                "workspace-c",
                title="Workspace 𝒞",
            )


class PloneintranetworkspaceWorkflowLayer(PloneintranetworkspaceLayer):
    """Shared fixtures for workflow tests"""

    def createPloneContents(self, portal):
        super().createPloneContents(portal)

        with api.env.adopt_user("admin"):
            # Creating users via api.user does not suffice. We need
            # approved (= published) ploneintranet.userprofile membrane
            # users in order for our ploneintranet.userprofile membrane
            # group 'intranet' to function properly.

            pi_api.userprofile.create(
                username="wsadmin", email="admin@test.com", approve=True
            )

            # wsmember is *not* a sitewide Member, but *is* a local TeamMember
            # to ensure permissions are not acquired when testing
            pi_api.userprofile.create(
                username="wsmember", email="member@test.com", approve=True
            )
            portal.groups.intranet.members.remove("wsmember")

            pi_api.userprofile.create(
                username="wsowner", email="owner@test.com", approve=True
            )

            pi_api.userprofile.create(
                username="wseditor", email="editor@test.com", approve=True
            )

            # intranet user is a sitewide Member, but not a local TeamMember
            pi_api.userprofile.create(
                username="intranet", email="intranet@test.com", approve=True
            )

            # extranet user is neither sitewide Member, nor local TeamMember
            pi_api.userprofile.create(
                username="extranet", email="extranet@test.com", approve=True
            )
            portal.groups.intranet.members.remove("extranet")

            # we removed users from the intranet group,
            # let's make the membrane the membrane tool aware of that
            notify(ObjectModifiedEvent(portal.groups.intranet))

        ws = portal.workspaces["demo-workspace"]
        # Allow the users to create testing content
        # This policy, will be then reset to fit the testcase
        ws.participant_policy = "producers"
        ws_adapter = IWorkspace(ws)
        ws_adapter.add_to_team("wsadmin", groups={"Admins"})
        ws_adapter.add_to_team("wsmember")
        ws_adapter.add_to_team("wsowner")

        with api.env.adopt_user("wsowner"):
            with api.env.adopt_roles(["TeamMember", "Contributor"]):
                api.content.create(ws, "Event", "owner-event")


PLONEINTRANET_WORKSPACE_FIXTURE = PloneintranetworkspaceLayer()
PLONEINTRANET_WORKSPACE_GROUPSPACE_FIXTURE = PloneintranetworkspaceGroupspaceLayer()
PLONEINTRANET_WORKSPACE_WORKFLOW_FIXTURE = PloneintranetworkspaceWorkflowLayer()

bases = (PLONEINTRANET_WORKSPACE_FIXTURE, MOCK_MAILHOST_FIXTURE)
PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING = SolrIntegrationTesting(
    bases=bases, name="PloneintranetworkspaceLayer:Integration"
)
PLONEINTRANET_WORKSPACE_GROUPSPACE_INTEGRATION_TESTING = SolrIntegrationTesting(
    bases=(PLONEINTRANET_WORKSPACE_GROUPSPACE_FIXTURE,),
    name="PloneintranetworkspaceGroupspaceLayer:Integration",
)
PLONEINTRANET_WORKSPACE_WORKFLOW_INTEGRATION_TESTING = SolrIntegrationTesting(
    bases=(PLONEINTRANET_WORKSPACE_WORKFLOW_FIXTURE, MOCK_MAILHOST_FIXTURE),
    name="PloneintranetworkspaceWorkflowLayer:Integration",
)
bases += (WSGI_SERVER_FIXTURE,)
PLONEINTRANET_WORKSPACE_FUNCTIONAL_TESTING = SolrFunctionalTesting(
    bases=bases, name="PloneintranetworkspaceLayer:Functional"
)
