from importlib.resources import files
from io import BufferedReader
from io import FileIO
from plone import api
from plone.app.testing.interfaces import SITE_OWNER_NAME
from plone.base.interfaces import INonStructuralFolder
from ploneintranet import api as pi_api
from ploneintranet.search.interfaces import IExcludeFromSearchResults
from ploneintranet.workspace.mailrouters import MailImporter
from ploneintranet.workspace.testing import PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING
from ploneintranet.workspace.tests.base import BaseTestCase
from slc.mailrouter.browser.views import FriendlyNameAddView


class TestMailin(BaseTestCase):
    """Test the Mailin feature"""

    layer = PLONEINTRANET_WORKSPACE_INTEGRATION_TESTING

    def setup_users(self):
        self.profile_allan = pi_api.userprofile.create(
            username="allan_neece", email="allan_neece@example.com", approve=True
        )
        self.profile_allan.reindexObject()

        self.profile_alice = pi_api.userprofile.create(
            username="alice_lindstrom",
            email="alice_lindstrom@example.com",
            approve=True,
        )
        self.profile_alice.reindexObject()

        # create the portal_membership records
        pm = api.portal.get_tool("portal_memberdata")
        acl = api.portal.get_tool("acl_users")
        pm.wrapUser(acl.getUser("allan_neece")).notifyModified()
        pm.wrapUser(acl.getUser("alice_lindstrom")).notifyModified()

    def create_workspace(self):
        """returns adapted workspace folder"""
        workspace_folder = api.content.create(
            self.workspace_container,
            "ploneintranet.workspace.workspacefolder",
            "mailin-workspace",
            title="Welcome to my workspace",
        )
        # Set the friendly name
        request = workspace_folder.REQUEST
        request.form["name"] = "mailinworkspace"
        request.form["form.submitted"] = "1"
        FriendlyNameAddView(workspace_folder, request)()
        self.add_user_to_workspace("alice_lindstrom", workspace_folder, {"Admins"})
        return workspace_folder

    def setUp(self):
        """ """
        pi_api.events.disable_previews()
        super().setUp()
        self.setup_users()
        self.workspace = self.create_workspace()
        self.logout()

    def tearDown(self):
        self.login(SITE_OWNER_NAME)
        self.workspace_container.manage_delObjects("mailin-workspace")
        super().tearDown()
        pi_api.events.disable_previews()

    def inject_mail(self, mail):
        """Mail is the filename of one of the mail
        you can find in the mailin folder
        """
        request = self.request.clone()
        path = str(files("ploneintranet.workspace.tests") / "mailin" / mail)
        request.stdin = BufferedReader(FileIO(path, "r"))
        # slc.mailrouter.browser.views.InjectionView
        view = api.content.get_view("mailrouter-inject", api.portal.get(), request)
        view()

    def test_get_or_create_import_folder(self):
        # This code is normally executed via the InjectionView helper.
        # Bring it directly under test here, to aid pdb-ing it.
        self.login(SITE_OWNER_NAME)
        api.portal.set_registry_record(
            "ploneintranet.workspace.mailin.folder.id", "INCOMING"
        )
        self.logout()

        self.login("alice_lindstrom")
        importer = MailImporter(self.workspace)
        import_folder = importer.get_or_create_import_folder()
        self.assertEqual("INCOMING", import_folder.id)
        self.assertEqual("INCOMING", import_folder.title)
        self.logout()

    def test_mailin_workspace(self):
        """The email is sent by alice who exists in the portal and has write
        permissions on the target workspace. This works.
        """
        self.assertEqual(api.user.get_current().name, "Anonymous User")
        self.inject_mail("mailin_workspace.eml")
        self.assert_email_imported_into(self.workspace)

    def test_mailin_incoming(self):
        """If configured, email is dropped in the designated import folder."""
        self.login(SITE_OWNER_NAME)
        api.portal.set_registry_record(
            "ploneintranet.workspace.mailin.folder.id", "EMAIL_IN"
        )
        api.portal.set_registry_record(
            "ploneintranet.workspace.mailin.folder.title", "Neue Emaïlé"
        )
        self.logout()

        self.assertEqual(api.user.get_current().name, "Anonymous User")
        self.inject_mail("mailin_workspace.eml")
        self.assertIn("EMAIL_IN", self.workspace)
        INCOMING = self.workspace.EMAIL_IN
        self.assertEqual("Neue Emaïlé", INCOMING.title)
        self.assert_email_imported_into(INCOMING)

    def assert_email_imported_into(self, context):
        # The email object has been created
        mails = [context[key] for key in context.keys() if key.startswith("mail")]
        self.assertTrue(len(mails) == 1)
        mail = mails[0]
        self.assertEqual(
            mail.mail_from, "Alice Lindstrom <alice_lindstrom@example.com>"
        )
        self.assertTupleEqual(
            mail.mail_to, ("Mailin Workspace <mailinworkspace@intranet.com>",)
        )
        self.assertTupleEqual(mail.mail_cc, ("foo@example.com", "bar.example.com"))
        self.assertTupleEqual(mail.mail_bcc, ())

        self.assertTrue(mail.mail_body.output.startswith("<html><head><meta"))
        self.assertTrue(INonStructuralFolder.providedBy(mail))

        # with two attachments
        self.assertEqual(mail["quaive.jpg"].portal_type, "Image")
        self.assertEqual(mail["quaive.jpg"].image.getSize(), 22758)
        self.assertTrue(IExcludeFromSearchResults.providedBy(mail["quaive.jpg"]))
        self.assertEqual(mail["signature.asc"].portal_type, "File")
        self.assertTrue(IExcludeFromSearchResults.providedBy(mail["signature.asc"]))
        self.assertIn(b"BEGIN PGP SIGNATURE", mail["signature.asc"].file.data)

        self.assertEqual(mail.Creator(), "alice_lindstrom")
        self.assertEqual(mail.getOwner().getId(), "alice_lindstrom")
        self.assertTrue(api.user.has_permission("View", user=mail.getOwner(), obj=mail))

        # and the original email
        mail["email.eml"].file.data.startswith(b"From")

        # Check the link in the mail body have been translated
        # from "cid:content-id" to "resolveuid/attachment-uid"
        self.assertIn(
            'src="resolveuid/%s"' % mail["quaive.jpg"].UID(), mail.mail_body.output
        )

        # We now check that the status updates are created for the mail
        mb = pi_api.microblog.get_microblog()
        pi_api.microblog.get_microblog()
        sus = list(mb.user_values("alice_lindstrom"))
        self.assertListEqual([mail], [su.content_context for su in sus])

    def test_invalid_sender(self):
        """The email contains a sender address unknown to the portal. The mail
        will not be delivered.
        """
        self.inject_mail("mailin_invalid_sender.eml")
        self.assertListEqual(
            [key for key in self.workspace if key.startswith("mail")], []
        )

    def test_no_write_permission(self):
        """The email is send by allan_neece, a valid sender address, but he
        has no write permission in the target folder. The email
        will not be delivered.
        """
        self.inject_mail("mailin_no_write_permission.eml")
        self.assertListEqual(
            [key for key in self.workspace if key.startswith("mail")], []
        )
