from email.iterators import _structure
from email.message import Message
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from django.core.mail import EmailMultiAlternatives
from django.test import SimpleTestCase


class RelatedPartTests(SimpleTestCase):
    def dump_message(self, message: Message) -> None:
        print(f"\n\n##### {self._testMethodName} #####")
        _structure(message)  # Dumps outline of message parts to stdout.
        print()
        # Uncomment to also dump the raw MIME message:
        # print(message.as_bytes().decode())
        # print()

    def setUp(self):
        self.email = EmailMultiAlternatives(body="Plain text body")

        self.image = MIMEImage(b"GIF89a...", "gif")
        self.image["Content-Disposition"] = "inline"
        self.image["Content-ID"] = "<image>"

        self.related = MIMEMultipart("related")
        self.related.attach(MIMEText("HTML body", "html"))
        self.related.attach(self.image)

    def test_raw_python_message(self):
        # No Django EmailMultiAlternative helpers. This achieves the goal:
        # multipart/alternative
        #     text/plain
        #     multipart/related
        #         text/html
        #         image/gif: Content-Disposition: inline; Content-ID: <image>
        message = Message()  # Python Message (not Django EmailMessage)
        message["Content-Type"] = "multipart/alternative"
        message.attach(MIMEText("Plain text body", "plain"))
        message.attach(self.related)
        self.dump_message(message)

    def test_attach_alternative(self):
        # TypeError: expected bytes-like object, not MIMEMultipart
        # in EmailMessage._create_alternatives ... _create_mime_attachment.
        self.email.attach_alternative(self.related, "multipart/related")
        message = self.email.message()  # TypeError
        self.dump_message(message)

    def test_attach_alternative_serialized(self):
        # multipart/alternative
        #     text/plain
        #     multipart/related: entire part, base64 encoded
        self.email.attach_alternative(self.related.as_bytes(), "multipart/related")
        message = self.email.message()
        self.dump_message(message)

    def test_attach_alternative_serialized_text(self):
        # multipart/alternative
        #     text/plain
        #     multipart/related: entire part, base64 encoded
        self.email.attach_alternative(self.related.as_bytes().decode(), "multipart/related")
        message = self.email.message()
        self.dump_message(message)

    def test_attach(self):
        # TypeError: expected bytes-like object, not MIMEMultipart
        # in EmailMessage._create_attachments ... _create_mime_attachment.
        self.email.attach("", self.related, "multipart/related")
        message = self.email.message()  # TypeError
        self.dump_message(message)

    def test_attach_serialized(self):
        # multipart/mixed
        #     text/plain
        #     multipart/related: entire part, base64 encoded
        self.email.attach("", self.related.as_bytes(), "multipart/related")
        message = self.email.message()
        self.dump_message(message)

    def test_attach_serialized_text(self):
        # multipart/mixed
        #     text/plain
        #     multipart/related: entire part, base64 encoded
        self.email.attach("", self.related.as_bytes().decode(), "multipart/related")
        message = self.email.message()
        self.dump_message(message)

    def test_attach_inline_image_directly(self):
        # This is not technically accurate (the inline image should be in a
        # related part with its html content), but most email clients will
        # render the inline image in the html as desired:
        #
        # multipart/mixed
        #     multipart/alternative
        #         text/plain
        #         text/html
        #     image/gif: Content-Disposition: inline; Content-ID: <image>
        self.email.attach_alternative("HTML body", "text/html")
        self.email.attach(self.image)
        message = self.email.message()
        self.dump_message(message)
