from collective.ftw.upgrade.interfaces import IUpgradeInformationGatherer
from plone import api
from ploneintranet.suite.testing import PLONEINTRANET_SUITE_INTEGRATION
from ploneintranet.suite.uninstall import ADDITIONAL_DEPENDENCIES
from Products.CMFPlone.utils import get_installer
from zope.component import getAdapter

import unittest


class TestSetup(unittest.TestCase):
    """Test that ploneintranet.suite is properly installed."""

    layer = PLONEINTRANET_SUITE_INTEGRATION

    def setUp(self):
        """Custom shared utility setup for tests."""
        self.portal = self.layer["portal"]
        self.installer = get_installer(self.portal, self.layer["request"])

    def test_product_installed(self):
        """Test if ploneintranet.suite is installed."""
        self.assertTrue(self.installer.is_product_installed("ploneintranet.suite"))

    def test_dependencies_are_installed(self):
        dependencies = []
        install_profile = self.installer.get_install_profile("ploneintranet.suite")
        for dependency in install_profile.get("dependencies", ()):
            dependency = dependency.split("profile-")[-1]
            dependency = dependency.split(":")[0]
            dependencies.append(str(dependency))
        for dependency in dependencies:
            self.assertTrue(
                self.installer.is_product_installed(dependency),
                f"Dependency not installed: {dependency}",
            )
        for depdendency in ADDITIONAL_DEPENDENCIES:
            self.assertTrue(
                self.installer.is_product_installed(dependency),
                f"Dependency not installed: {dependency}",
            )

    def test_no_pending_upgrades(self):
        ps = api.portal.get_tool("portal_setup")
        pending_upgrades = set(ps.listProfilesWithPendingUpgrades())
        # We allow pending upgrades from Plone
        self.assertSetEqual(pending_upgrades - {"Products.CMFPlone:plone"}, set())

    def test_registry_many_users_and_groups(self):
        self.assertTrue(api.portal.get_registry_record("plone.many_users"))
        self.assertTrue(api.portal.get_registry_record("plone.many_groups"))

    def test_intranet_groups_members(self):
        self.assertIn("alice_lindstrom", self.portal.groups.intranet.members)
        self.assertNotIn("ulysses_grant", self.portal.groups.intranet.members)
        self.assertNotIn("robinson_crusoe", self.portal.groups.intranet.members)

    def test_intids_ok(self):
        """Check that after everything is set up we have
        a proper initid catalog
        """
        view = self.portal.restrictedTraverse("pi-intids")
        self.assertListEqual(view.keys_with_a_broken_path, [])
        self.assertListEqual(view.refs_with_a_broken_path, [])

    def test_resources(self):
        base_url = "++theme++ploneintranet.theme/generated/{}"
        # It seems we only need 1 favicon these days
        for resource in ("assets/quaive/favicon/touch-icon.png",):
            self.assertIsNotNone(
                self.portal.restrictedTraverse(base_url.format(resource))
            )

    def test_workflows_manage_access_contents_information(self):
        pw = api.portal.get_tool("portal_workflow")
        wfs = [
            wf
            for wf in pw.objectValues()
            if "Access contents information" not in wf.permissions
            and "View" in wf.permissions
        ]
        self.assertListEqual(wfs, [])

    def test_no_gs_circular_dependencies(self):
        """This test will raise a collective.ftw.upgrade.exceptions.CyclicDependencies
        exception if we will have circular dependencies between Generic Setup profiles
        """
        adapter = getAdapter(self.portal.portal_setup, IUpgradeInformationGatherer)
        self.assertIsInstance(adapter.get_upgrades(), list)

    def test_proper_role_mappings_after_setup(self):
        self.assertEqual(
            api.content.get_state(self.portal.apps.preferences),
            "published",
        )
        self.assertSetEqual(
            {
                role["name"]
                for role in self.portal.apps.preferences.rolesOfPermission("View")
                if role["selected"]
            },
            {
                "Editor",
                "Manager",
                "Member",
                "Owner",
                "Reader",
                "Site Administrator",
            },
        )

    def test_imagebank_installed(self):
        self.assertTrue(
            self.installer.is_product_installed("ploneintranet.imagebank"),
            "ploneintranet.imagebank should be installed as a dependency",
        )


class TestUninstall(unittest.TestCase):
    """Test that ploneintranet.suite is properly uninstalled."""

    layer = PLONEINTRANET_SUITE_INTEGRATION

    def setUp(self):
        """Custom shared utility setup for tests."""
        self.portal = self.layer["portal"]
        self.installer = get_installer(self.portal, self.layer["request"])
        self.installer.uninstall_product("ploneintranet.suite")

    def test_uninstall(self):
        """Test if ploneintranet.suite is cleanly uninstalled."""
        self.assertFalse(self.installer.is_product_installed("ploneintranet.suite"))

    def test_dependencies_are_uninstalled(self):
        """Test if deps from the ploneintranet-namespace are uninstalled.
        Also some additional deps should be uninstalled.
        """
        dependencies = []
        install_profile = self.installer.get_install_profile("ploneintranet.suite")
        for dependency in install_profile.get("dependencies", ()):
            dependency = dependency.split("profile-")[-1]
            dependency = dependency.split(":")[0]
            dependencies.append(str(dependency))
        for dependency in dependencies:
            if (
                dependency.startswith("ploneintranet.")
                or dependency.startswith("quaive.")
                or dependency in ADDITIONAL_DEPENDENCIES
            ):
                self.assertFalse(
                    self.installer.is_product_installed(dependency),
                    f"Dependency still installed: {dependency}",
                )
            else:
                self.assertTrue(
                    self.installer.is_product_installed(dependency),
                    f"Dependency should not be uninstalled: {dependency}",
                )
