from plone import api
from plone.app import testing
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from ploneintranet import api as pi_api
from ploneintranet.library.behaviors.publish import IPublishWidely
from ploneintranet.library.testing import PloneintranetLibrarySolrLayer
from ploneintranet.library.testing import SolrIntegrationTestCase
from zope.interface.verify import verifyObject


class PublishWidelyLayer(PloneintranetLibrarySolrLayer):
    def setUpPloneSite(self, portal):
        setRoles(portal, TEST_USER_ID, ("Manager",))
        source_folder = api.content.create(
            type="Folder", title="Source folder", container=portal
        )
        source_document = api.content.create(
            type="Document",
            title="Holidays previous year",
            container=source_folder,
        )
        api.content.transition(source_document, "publish")
        library_section = api.content.create(
            type="ploneintranet.library.section",
            title="Human Resources",
            container=portal.library,
        )
        api.content.create(
            type="ploneintranet.library.folder",
            title="Holidays",
            container=library_section,
        )
        section = portal.library["human-resources"]
        folder = section["holidays"]
        api.content.create(
            type="ploneintranet.library.folder", title="A subfolder", container=folder
        )
        api.content.create(
            type="ploneintranet.library.folder",
            title="Holidays Galore",
            container=section,
        )
        setRoles(portal, TEST_USER_ID, ("Reviewer", "Contributor"))
        super().setUpPloneSite(portal)


LIBRARY_PUBLISH_WIDELY_FIXTURE = PublishWidelyLayer()
LIBRARY_PUBLISH_WIDELY_TESTING = testing.IntegrationTesting(
    bases=(LIBRARY_PUBLISH_WIDELY_FIXTURE,),
    name="PloneintranetPublishWidelyLayer:Integration",
)


class PublishWidelyIntegrationTestCase(SolrIntegrationTestCase):

    layer = LIBRARY_PUBLISH_WIDELY_TESTING

    def setUp(self):
        super().setUp()
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]
        self.source_folder = self.portal["source-folder"]
        self.source_document = self.source_folder["holidays-previous-year"]
        self.library_section = self.portal.library["human-resources"]
        self.library_folder = self.library_section["holidays"]
        self.library_subfolder = self.library_folder["a-subfolder"]


class TestPublishWidely(PublishWidelyIntegrationTestCase):
    def test_behavior_interface(self):
        adapted = IPublishWidely(self.source_document)
        self.assertTrue(verifyObject(IPublishWidely, adapted))

    def test_behavior_active_document(self):
        content = self.source_document
        self.assertFalse(IPublishWidely.providedBy(content))
        adapted = IPublishWidely(content)
        self.assertTrue(IPublishWidely.providedBy(adapted))

    def test_behavior_active_file(self):
        content = api.content.create(
            type="File",
            title="Holidays previous year file",
            container=self.source_folder,
        )
        self.assertFalse(IPublishWidely.providedBy(content))
        adapted = IPublishWidely(content)
        self.assertTrue(IPublishWidely.providedBy(adapted))

    def test_behavior_active_image(self):
        content = api.content.create(
            type="Image",
            title="Holidays previous year image",
            container=self.source_folder,
        )
        self.assertFalse(IPublishWidely.providedBy(content))
        adapted = IPublishWidely(content)
        self.assertTrue(IPublishWidely.providedBy(adapted))

    def test_behavior_active_link(self):
        content = api.content.create(
            type="Link",
            title="Holidays previous year link",
            container=self.source_folder,
        )
        api.content.transition(content, "publish")
        self.assertFalse(IPublishWidely.providedBy(content))
        adapted = IPublishWidely(content)
        self.assertTrue(IPublishWidely.providedBy(adapted))

    def test_permission(self):
        adapted = IPublishWidely(self.source_document)
        self.assertTrue(adapted.can_publish_widely())
        setRoles(self.portal, TEST_USER_ID, ("Member",))
        self.assertFalse(adapted.can_publish_widely())

    def test_workflow(self):
        adapted = IPublishWidely(self.source_document)
        self.assertTrue(adapted.can_publish_widely())
        api.content.transition(self.source_document, "retract")
        self.assertFalse(adapted.can_publish_widely())

    def test_workflow_noworkflow(self):
        content = api.content.create(
            type="Image",
            title="Holidays previous year image",
            container=self.source_folder,
        )
        adapted = IPublishWidely(content)
        self.assertTrue(adapted.can_publish_widely())

    def test_location(self):
        content = api.content.create(
            type="Document", title="Library document", container=self.library_folder
        )
        api.content.transition(content, "publish")
        adapted = IPublishWidely(content)
        self.assertFalse(adapted.can_publish_widely())

    def test_copy_to_target_section_invalid(self):
        adapted = IPublishWidely(self.source_document)
        new = adapted.copy_to(self.library_section)  # invalid target
        self.assertEqual(None, new)

    def test_copy_to(self):
        adapted = IPublishWidely(self.source_document)
        new = adapted.copy_to(self.library_folder)
        self.assertIn(new, self.library_folder.objectValues())
        self.assertEqual(new.title, self.source_document.title)

    def test_relation_source(self):
        adapted = IPublishWidely(self.source_document)
        self.assertEqual(adapted.source(), None)
        new = adapted.copy_to(self.library_folder)
        new_adapted = IPublishWidely(new)
        self.assertEqual(new_adapted.source(), self.source_document)
        self.assertNotEqual(new_adapted.source(), None)

    def test_relation_target(self):
        adapted = IPublishWidely(self.source_document)
        self.assertEqual(adapted.target(), None)
        new = adapted.copy_to(self.library_folder)
        self.assertEqual(adapted.target(), new)
        self.assertNotEqual(adapted.target(), None)

    def test_publish_only_once(self):
        adapted = IPublishWidely(self.source_document)
        self.assertTrue(adapted.can_publish_widely())
        adapted.copy_to(self.library_folder)
        self.assertFalse(adapted.can_publish_widely())

    def test_can_update_target(self):
        adapted = IPublishWidely(self.source_document)
        self.assertFalse(adapted.can_update_widely())
        adapted.copy_to(self.library_folder)
        self.assertTrue(adapted.can_update_widely())

    @pi_api.events.notifications_disabled
    def test_update_target(self):
        adapted = IPublishWidely(self.source_document)
        adapted.copy_to(self.library_folder)
        self.assertFalse(adapted.has_updated_source())
        # reindex to update modified stamp
        self.source_document.reindexObject()
        self.assertTrue(adapted.has_updated_source())
        # retract and re-publish
        adapted.retract()
        adapted.copy_to(self.library_folder)
        self.assertFalse(adapted.has_updated_source())

    def test_retract_permission_no_target(self):
        # No target means no permission to retract
        adapted = IPublishWidely(self.source_document)
        self.assertFalse(adapted.can_retract_widely())

    def test_retract_permission_with_target(self):
        adapted = IPublishWidely(self.source_document)
        adapted.copy_to(self.library_folder)
        self.assertTrue(adapted.can_retract_widely())

    def test_retract_permission(self):
        adapted = IPublishWidely(self.source_document)
        adapted.copy_to(self.library_folder)
        # revoke the Owner role from the target and the parent folders
        # in the library to take away the permission to delete.
        user = api.user.get_current()
        api.user.revoke_roles(user=user, obj=adapted.target(), roles=["Owner"])
        api.user.revoke_roles(user=user, obj=self.library_section, roles=["Owner"])
        api.user.revoke_roles(user=user, obj=self.library_folder, roles=["Owner"])
        self.assertFalse(adapted.can_retract_widely())

    def test_retract_no_target(self):
        adapted = IPublishWidely(self.source_document)
        self.assertFalse(adapted.retract())

    @pi_api.events.notifications_disabled
    def test_retract(self):
        adapted = IPublishWidely(self.source_document)
        adapted.copy_to(self.library_folder)
        target_path = "/".join(adapted.target().getPhysicalPath())
        self.assertTrue(self.portal.restrictedTraverse(target_path))
        self.assertTrue(adapted.retract())
        self.assertRaises(KeyError, self.portal.restrictedTraverse, target_path)

    def test_publish_widely_target_structure(self):
        # Folders that are deeper in the library structure are available as targets
        # for publishing
        view = api.content.get_view(
            "panel-publish-to-library",
            context=self.source_document,
            request=self.request.clone(),
        )
        tree = view.target_tree()
        self.assertEqual(tree[0]["title"], "Human Resources")
        self.assertListEqual(
            [item["id"] for item in tree[0]["content"]],
            [
                "human-resources/generic",
                "human-resources/holidays",
                "human-resources/holidays/a-subfolder",
                "human-resources/holidays-galore",
            ],
        )

    def test_copy_to_deep_folder(self):
        # We can publish content to folders that are deeper in the library structure
        request = self.request.clone()
        request["target_path"] = "/".join(self.library_subfolder.getPhysicalPath())
        view = api.content.get_view(
            "panel-publish-to-library", context=self.source_document, request=request
        )
        self.assertListEqual(self.library_subfolder.objectIds(), [])
        view()
        self.assertIn(self.source_document.getId(), self.library_subfolder.objectIds())


class TestPublishWidelyBrowserFlatStructure(PublishWidelyIntegrationTestCase):
    def setUp(self):
        super().setUp()
        ttool = api.portal.get_tool("portal_types")
        type_info_section = ttool["ploneintranet.library.section"]
        type_info_folder = ttool["ploneintranet.library.folder"]
        type_info_section.allowed_content_types = type_info_folder.allowed_content_types

    def test_copy_to_target_section_allowed(self):
        adapted = IPublishWidely(self.source_document)
        target = self.portal.library["human-resources"]
        new = adapted.copy_to(target)
        self.assertIn(new, target.objectValues())
        self.assertEqual(new.title, self.source_document.title)

    def test_publish_widely_target_structure_with_sections(self):
        # Folders that are deeper in the library structure are available as targets
        # for publishing.
        # In this case, the section appears as the respective first element of every
        # subset
        view = api.content.get_view(
            "panel-publish-to-library",
            context=self.source_document,
            request=self.request.clone(),
        )
        tree = view.target_tree()
        self.assertEqual(tree[0]["title"], "Human Resources")
        self.assertListEqual(
            [item["id"] for item in tree[0]["content"]],
            [
                "human-resources",
                "human-resources/generic",
                "human-resources/holidays",
                "human-resources/holidays/a-subfolder",
                "human-resources/holidays-galore",
            ],
        )
