from collective.workspace.interfaces import IHasWorkspace
from collective.workspace.interfaces import IWorkspace
from importlib.resources import files
from plone import api
from plone.api.exc import InvalidParameterError
from plone.namedfile.file import NamedBlobImage
from ploneintranet import api as pi_api
from ploneintranet.testing import temporary_registry_record
from ploneintranet.workspace.config import TEMPLATES_FOLDER
from ploneintranet.workspace.tests.base import BaseTestCase
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent


class TestAddWorkspace(BaseTestCase):
    def test_custom_get_id_on_copy_move(self):
        """We have a custom _get_id that allows api.content.copy
        to immediately copy templates with the proper id without the need
        to perform a rename
        """
        container = self.portal.workspaces
        obj = container.listFolderContents()[0]
        obj_copy = api.content.copy(obj, container)
        # default behavior is the standard one
        self.assertEqual(obj_copy.getId(), "copy_of_demo-workspace")
        # we force a custom id
        self.request.set("_copy_move_suggested_id", "custom-id")
        obj_copy = api.content.copy(obj, container)
        obj_copy.getId()
        self.assertEqual(obj_copy.getId(), "custom-id")
        obj_copy = api.content.copy(obj, container)
        self.assertEqual(obj_copy.getId(), "copy_of_custom-id")

    def test_add_workspacefolder(self):
        """check that we can create our workspace folder type,
        and that it provides the collective.workspace behaviour
        """
        self.login_as_portal_owner()
        workspace_folder = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
            title="Welcome to my workspacé",
        )

        self.assertTrue(
            IHasWorkspace.providedBy(workspace_folder),
            "Workspace type does not provide the" "collective.workspace behaviour",
        )

        # does the view work?
        view = workspace_folder.restrictedTraverse("@@view")
        html = view()
        self.assertIn(
            workspace_folder.title, html, "Workspace title not found on view page"
        )

    def test_cannot_add_workspace_in_portal(self):
        """
        workspaces cannot be nested
        """
        self.login_as_portal_owner()
        self.assertRaises(
            InvalidParameterError,
            api.content.create,
            self.portal,
            "ploneintranet.workspace.workspacefolder",
            "banned-workspace",
        )

    def test_cannot_add_sub_workspace(self):
        """
        workspaces cannot be nested
        """
        self.login_as_portal_owner()
        workspace = api.content.create(
            container=self.workspace_container,
            type="ploneintranet.workspace.workspacefolder",
            id="workspace-1",
        )
        self.assertRaises(
            InvalidParameterError,
            api.content.create,
            workspace,
            "ploneintranet.workspace.workspacefolder",
            "workspace-2",
        )

    def test_add_workspacecontainer(self):
        """
        Check that WorkspaceContainer can be added to site root
        """
        self.login_as_portal_owner()
        api.content.create(
            self.portal,
            "ploneintranet.workspace.workspacecontainer",
            "test-workspaces",
            title="Test Workspaces",
        )
        self.assertIn("test-workspaces", self.portal)

    def test_cannot_add_workspacecontainer_inside_workspace(self):
        """
        Check that WorkspaceContainer cannot be added inside a workspace
        """
        self.login_as_portal_owner()
        ws = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "workspace-1",
            title="Workspace 1",
        )
        self.assertRaises(
            InvalidParameterError,
            api.content.create,
            ws,
            "ploneintranet.workspace.workspacecontainer",
            "workspaces",
        )

    def test_can_add_workspace_inside_workspacecontainer(self):
        """
        Check that workspaces can be added inside workspace container.
        The workspace container is already being added in the setuphandler.
        """
        self.login_as_portal_owner()
        wsc = getattr(self.portal, "workspaces")
        api.content.create(
            wsc,
            "ploneintranet.workspace.workspacefolder",
            "workspace-1",
            title="Workspace 1",
        )
        self.assertIn("workspace-1", wsc)

    def test_cannot_add_other_content_in_workspacecontainer(self):
        """
        Check that *only* workspaces can be added inside workspace container
        """
        self.login_as_portal_owner()
        wsc = getattr(self.portal, "workspaces")
        self.assertRaises(
            InvalidParameterError, api.content.create, wsc, "Document", "doc-1"
        )

    def test_attributes(self):
        """
        Check that we can access and set the attributes
        """
        self.login_as_portal_owner()
        wsc = getattr(self.portal, "workspaces")
        ws = api.content.create(
            wsc,
            "ploneintranet.workspace.workspacefolder",
            "workspace-1",
            title="Workspace 1",
        )
        self.assertEqual(ws.calendar_visible, False)
        self.assertEqual(ws.email, "")

        ws.calendar_visible = True
        ws.email = "test@testing.net"

        self.assertEqual(ws.calendar_visible, True)
        self.assertEqual(ws.email, "test@testing.net")

        self.assertEqual(ws.hero_image, None)

        data = (
            files("ploneintranet.workspace") / "tests" / "hero_image.jpg"
        ).read_bytes()
        ws.hero_image = NamedBlobImage(data=data, filename="hero_image.jpg")

        self.assertEqual(len(ws.hero_image.data), len(data))


class TestAddWorkspaceView(BaseTestCase):
    def setUp(self):
        super().setUp()

        self.templates_container = self.portal.get(TEMPLATES_FOLDER)
        with api.env.adopt_user("admin"):
            pi_api.userprofile.create(
                username="johndoe", email="johndoe@test.com", approve=True
            )
            self.portal.groups.intranet.members.add("johndoe")
            notify(ObjectModifiedEvent(self.portal.groups.intranet))
            self.template = api.content.create(
                self.templates_container,
                "ploneintranet.workspace.workspacefolder",
                "example-template",
                title="Welcome to my workspace template",
            )
        self.add_user_to_workspace("johndoe", self.template)

    def _get_add_view(self, params={}):
        request = self.request.clone()
        request.form.update(params)
        return api.content.get_view(
            "add_workspace", context=self.portal.workspaces, request=request
        )

    def test_add_secret_workspace(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "my workspace", "workspace-type": "secret"}
            )
            add_view()
        ws = self.workspace_container["my-workspace"]
        self.assertEqual(ws.title, "my workspace")
        self.assertFalse(ws.visible_to_intranet_users)
        self.assertFalse(ws.accessible_to_intranet_users)
        self.assertEqual(api.content.get_state(ws), "secret")
        self.assertEqual(ws.join_policy, "admin")
        self.assertEqual(ws.participant_policy, "producers")

    def test_add_private_workspace(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "my workspace", "workspace-type": "private"}
            )
            add_view()
        ws = self.workspace_container["my-workspace"]
        self.assertEqual(ws.title, "my workspace")
        self.assertTrue(ws.visible_to_intranet_users)
        self.assertFalse(ws.accessible_to_intranet_users)
        self.assertEqual(api.content.get_state(ws), "secret")
        self.assertEqual(ws.join_policy, "team")
        self.assertEqual(ws.participant_policy, "moderators")

    def test_add_open_workspace(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "my workspace", "workspace-type": "open"}
            )
            add_view()
        ws = self.workspace_container["my-workspace"]
        self.assertEqual(ws.title, "my workspace")
        self.assertTrue(ws.visible_to_intranet_users)
        self.assertTrue(ws.accessible_to_intranet_users)
        self.assertEqual(api.content.get_state(ws), "secret")
        self.assertEqual(ws.join_policy, "team")
        self.assertEqual(ws.participant_policy, "publishers")

    def test_add_superspace(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {
                    "title": "A superspace",
                    "workspace-type": "ploneintranet.workspace.superspace",
                }
            )
            add_view()
        ws = self.workspace_container["a-superspace"]
        self.assertEqual(ws.title, "A superspace")
        self.assertTrue(ws.visible_to_intranet_users)
        self.assertTrue(ws.accessible_to_intranet_users)
        self.assertEqual(api.content.get_state(ws), "secret")
        self.assertEqual(ws.join_policy, "admin")
        self.assertEqual(ws.participant_policy, "consumers")

    def test_add_template_via_view_preserve_owner(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "WS", "workspace-type": "example-template"}
            )
            ws = add_view.create_from_template()

        self.assertEqual(ws.getOwner().getId(), "johndoe")

        add_view.request.__annotations__.clear()
        with api.env.adopt_user("johndoe"):
            with temporary_registry_record(
                "ploneintranet.workspace.preserve_template_ownership", True
            ):
                # This has no effect for regular workspaces
                ws = add_view.create_from_template()
        self.assertEqual(ws.getOwner().getId(), "johndoe")

    def test_add_template_via_view_preserve_state(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "WS", "workspace-type": "example-template"}
            )
            ws = add_view.create_from_template()
        self.assertEqual(api.content.get_state(ws), "secret")

    def test_add_template_via_view_preserve_visible_to_intranet_users(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "WS", "workspace-type": "example-template"}
            )
            ws = add_view.create_from_template()
        self.assertFalse(ws.visible_to_intranet_users)

        add_view.request.__annotations__.clear()

        # Now make it visible to intranet users
        self.template.visible_to_intranet_users = True
        with api.env.adopt_user("johndoe"):
            ws = add_view.create_from_template()
        self.assertTrue(ws.visible_to_intranet_users)

    def test_add_template_via_view_preserve_accessible_to_intranet_users(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view(
                {"title": "WS", "workspace-type": "example-template"}
            )
            ws = add_view.create_from_template()
        self.assertFalse(ws.accessible_to_intranet_users)

        add_view.request.__annotations__.clear()

        # Now make it accessible to intranet users
        self.template.accessible_to_intranet_users = True
        with api.env.adopt_user("johndoe"):
            ws = add_view.create_from_template()
        self.assertTrue(ws.accessible_to_intranet_users)

    def test_template_member_can_see_template_in_menu(self):
        with api.env.adopt_user("johndoe"):
            add_view = self._get_add_view()
        self.assertIn("example-template", add_view.all_templates_dict)

    def test_template_nonmember_cannot_see_template_in_menu(self):
        api.user.create(username="maryjane", email="maryjane@test.com")
        with api.env.adopt_user("maryjane"):
            add_view = self._get_add_view()
            self.assertNotIn("example-template", add_view.all_templates_dict)


class TestAddUsersToWorkspace(BaseTestCase):
    def _create_workspace(self):
        """returns adapted workspace folder"""
        workspace_folder = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
            title="Welcome to my workspace",
        )
        return IWorkspace(workspace_folder)

    def _create_unadapted_workspace(self):
        """Return unadapted workspace object"""
        workspace_folder = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "example-workspace",
            title="Welcome to my workspace",
        )
        return workspace_folder

    def _create_user(self, name="testuser", password="$uper5ecreT"):
        """
        helper method for creating a test user
        :param name: username
        :param password: password for the user
        :returns: user object
        :rtype: MemberData

        """
        user = api.user.create(email="test@user.com", username=name, password=password)
        return user

    def test_add_user_to_workspace(self):
        """check that we can add a new user to a workspace"""
        self.login_as_portal_owner()
        ws = self._create_workspace()
        user = self._create_user()
        ws.add_to_team(user.getId())
        self.assertIn(user.getId(), [x for x in list(ws.members)])

    def test_add_admin_to_workspace(self):
        """check that site admin can add team admin to the workspace"""
        self.login_as_portal_owner()
        ws = self._create_unadapted_workspace()
        user = self._create_user()
        groups = api.group.get_groups()
        group_names = [x.getName() for x in groups]
        group_name = "Admins:%s" % (api.content.get_uuid(ws))
        self.assertIn(group_name, group_names)
        workspace = IWorkspace(ws)
        workspace.add_to_team(user.getId(), groups={"Admins"})

        portal = api.portal.get()
        pgroups = portal.portal_groups.getGroupById(group_name)
        member_ids = pgroups.getGroup().getMemberIds()
        self.assertIn(user.getId(), member_ids)
