from email.header import decode_header
from plone import api
from plone.app.testing import logout
from plone.app.testing.interfaces import SITE_OWNER_NAME
from plone.testing import zope as zope_testing
from ploneintranet import api as pi_api
from ploneintranet.workspace.interfaces import IWorkspaceAppContentLayer
from ploneintranet.workspace.testing import PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING
from unittest import TestCase
from zope.interface import alsoProvides

import email


class TestWorkSpaceWorkflow(TestCase):
    layer = PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING

    def setUp(self):
        self.app = self.layer["app"]
        self.portal = self.layer["portal"]
        self.request = self.layer["request"]
        pi_api.events.disable_previews()
        self.workspace_container = self.portal.workspaces
        zope_testing.login(self.app["acl_users"], SITE_OWNER_NAME)
        self.workspace = api.content.create(
            self.portal.workspaces,
            "ploneintranet.workspace.workspacefolder",
            "notifications-workspace-container",
            title="Workspace container for testing email notifications",
        )
        self.mailhost = self.portal.MailHost

    def get_email_invitees_view(self, obj):
        """Gets the "email_invitees email"
        in the context of the Plone event obj and
        with a clean request
        """
        return api.content.get_view("email_invitees", obj, self.request.clone())

    def test_email_events(self):
        """This is going to tests that the mail have been sent correctly"""
        obj = api.content.create(self.workspace, type="Event", title="invitees_members")

        # We have a send method which return the number of errors
        # while sending the email.
        view = self.get_email_invitees_view(obj)
        # no error thrown
        self.assertEqual(view.send(), 0)
        # no email sent
        self.assertEqual(len(self.mailhost.messages), 0)

        # It should be 0 in invitees contains invalid data.
        obj.invitees = "i-dont-exist"
        view = self.get_email_invitees_view(obj)
        # no error thrown
        self.assertEqual(view.send(), 0)
        # no email sent
        self.assertEqual(len(self.mailhost.messages), 0)

        # With valid data, an email should be sent out.
        pi_api.userprofile.create(username="invitee", email="invitee@example.com")
        obj.invitees = "invitee"
        view = self.get_email_invitees_view(obj)
        pi_api.userprofile.create(username="inviter", email="inviter@example.com")
        with api.env.adopt_user(username="inviter"):
            # no error thrown
            self.assertEqual(view.send(), 0)
        # 1 email sent
        self.assertEqual(len(self.mailhost.messages), 1)
        # and we have valid messages
        msgs = list(view.iter_messages())
        self.assertEqual(len(msgs), 1)
        msg = msgs[0]
        self.assertTrue(msg["Subject"].startswith("invitees_members: 20"))

        # Note that for the inviter we don't have a name before the email address
        # but for the invitee we do. This is because user.fullname is empty for
        # both, but for the invitee the code falls back to using the userid.
        reply_to = decode_header(msg["Reply-To"])[0][0].decode("utf-8")
        self.assertEqual(reply_to, " <inviter@example.com>")
        self.assertEqual(msg["To"], "invitee <invitee@example.com>")
        html = msg.get_payload()[0]
        self.assertTrue(html.get_payload().startswith("<p>Dear Mr./Ms. invitee,</p>\n"))

        # The From header is added automatically to the email by api.portal.send_email
        raw_mail = self.mailhost.messages[0]
        mail = email.message_from_bytes(raw_mail, policy=email.policy.default)
        self.assertEqual(mail["From"], "Plone site <noreply@example.com>")

    def test_agenda_items(self):
        event = api.content.create(self.workspace, type="Event", title="Test assignees")
        document = api.content.create(
            self.workspace, type="Document", title="Document in Agenda"
        )
        # Test default
        self.assertEqual(event.agenda_items, [])
        event.agenda_items = [
            "Prologue",
            document.UID(),
            "1234567890abcdef1234567890abcdef",
            "☰",
            "Epilogue",
        ]

        # Test that the view understands when an agenda item is a UID
        request = self.request.clone()
        alsoProvides(request, IWorkspaceAppContentLayer)
        event_view = api.content.get_view("event_view", event, request)
        # Check that we do not display underesolved UIDS
        self.assertEqual(len(event.agenda_items), 5)
        self.assertEqual(len(event_view.get_agenda_items()), 4)

        for item in event_view.get_agenda_items():
            if item["brain"]:
                self.assertTrue(item["read_only"])
            else:
                self.assertFalse(item["read_only"])

        # Check permissions as someone who cannot query the catalog
        event_view.request.__annotations__.pop("plone.memoize")
        logout()
        for item in event_view.get_agenda_items():
            self.assertTrue(item["read_only"])
