from plone import api
from ploneintranet import api as pi_api
from ploneintranet.userprofile.pas.pi_email_authenticator import (
    EmailAuthenticatorPlugin,
)
from ploneintranet.userprofile.testing import (
    PLONEINTRANET_USERPROFILE_INTEGRATION_TESTING,
)
from Products.statusmessages.interfaces import IStatusMessage
from unittest import TestCase
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent


class TestPIRecursiveGroupsPlugin(TestCase):
    """Test installation of ploneintranet.userprofile into Plone."""

    layer = PLONEINTRANET_USERPROFILE_INTEGRATION_TESTING

    def setUp(self):
        self.app = self.layer["app"]
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]

    def test_recursive_groups(self):
        """Check if our recursive groups plugin is working properly"""
        pi_api.userprofile.create("foo")
        plugin = self.portal.acl_users.pi_recursive_groups

        foo = api.user.get("foo")

        def _check_foo_groups():
            return set(plugin.getGroupsForPrincipal(foo, request=self.request.clone()))

        self.assertSetEqual(_check_foo_groups(), set())

        pi_api.workgroup.create("baz", members={"foo"})
        bar = pi_api.workgroup.create("bar", members={"baz"})

        self.assertSetEqual(_check_foo_groups(), {"bar", "baz"})

        pi_api.workgroup.create("bax", members={"foo"})

        foo = api.user.get("foo")
        self.assertSetEqual(_check_foo_groups(), {"bar", "bax", "baz"})

        bar.members.remove("baz")
        notify(ObjectModifiedEvent(bar))

        self.assertSetEqual(_check_foo_groups(), {"bax", "baz"})


class TestEmailAuthenticatorPlugin(TestCase):
    """Test the 2FA plugin for Quaive."""

    layer = PLONEINTRANET_USERPROFILE_INTEGRATION_TESTING

    def setUp(self):
        self.app = self.layer["app"]
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]
        self.plugin = EmailAuthenticatorPlugin(
            "pi_email_authenticator", "PloneIntranet Email Authenticator PAS Plugin"
        )
        self.plugin.REQUEST = self.request.clone()
        self.profile = pi_api.userprofile.create(
            username="johndoe", email="johndoe@doe.com", approve=True, password="secret"
        )

    def test_email_authentication_process(self):
        """Check if our email authentication plugin is working properly"""
        self.plugin.authenticateCredentials(
            {
                "extractor": "foo",
                "login": "johndoe",
                "password": "secret",
            }
        )
        view = api.content.get_view(
            "email-verification-check-token", self.profile, self.request.clone()
        )
        self.assertRegex(view.token_storage["token"], r"[a-f0-9]{32}")

        # Check that the token is valid
        view.publishTraverse(view.request, view.token_storage["token"])
        self.assertTrue(view.verify_token())

        # Check that after calling the view:
        view()

        # the user is logged in
        messages = IStatusMessage(view.request).show()
        self.assertListEqual(
            [message.__dict__ for message in messages],
            [{"message": "You are now logged in", "type": "info"}],
        )

        # the token is canceled
        self.assertFalse(view.token_storage)

        # and redirected to the home page
        self.assertDictEqual(
            view.request.response.headers, {"location": "http://nohost/plone"}
        )

    def test_email_authentication_invalid_token(self):
        view = api.content.get_view(
            "email-verification-check-token", self.profile, self.request.clone()
        )
        view.publishTraverse(view.request, "bogus")
        self.assertFalse(view.verify_token())
        # Check that after calling the view:
        view()

        # the user is not logged in
        messages = IStatusMessage(view.request).show()
        self.assertListEqual(
            [message.__dict__ for message in messages],
            [{"message": "Invalid token", "type": "info"}],
        )
        # and redirected to the login page
        self.assertDictEqual(
            view.request.response.headers,
            {"location": "http://nohost/plone/require_login"},
        )

    def test_email_authentication_came_from(self):
        """Check if our email authentication plugin is working properly"""
        self.request.set("came_from", "http://nohost/plone/profiles")
        self.plugin.authenticateCredentials(
            {
                "extractor": "foo",
                "login": "johndoe",
                "password": "secret",
            }
        )
        view = api.content.get_view(
            "email-verification-check-token", self.profile, self.request.clone()
        )
        view.publishTraverse(view.request, view.token_storage["token"])

        # Check that after calling the view:
        view()

        # the user is redirected to the profiles page
        self.assertDictEqual(
            view.request.response.headers,
            {"location": "http://nohost/plone/profiles"},
        )
