# -*- coding: utf-8 -*-
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""

from io import StringIO
import tempfile
import sys
from contextlib import contextmanager
from functools import wraps

from django.utils.encoding import force_bytes, force_text

MEDIA_ROOT = tempfile.mkdtemp()


@contextmanager
def captured_output():
    new_out, new_err = StringIO(), StringIO()
    old_out, old_err = sys.stdout, sys.stderr
    try:
        sys.stdout, sys.stderr = new_out, new_err
        yield sys.stdout, sys.stderr
    finally:
        sys.stdout, sys.stderr = old_out, old_err


class stderr_output(object):
    def __init__(self, output):
        self.output = output

    def __call__(self, func):
        @wraps(func)
        def f(testcase, *args, **kwargs):
            with captured_output() as (out, err):
                ret = func(testcase, *args, **kwargs)
            testcase.assertEqual(self.output, err.getvalue())
            return ret

        return f


class stdout_output(object):
    def __init__(self, output):
        self.output = output

    def __call__(self, func):
        @wraps(func)
        def f(testcase, *args, **kwargs):
            with captured_output() as (out, err):
                ret = func(testcase, *args, **kwargs)
            testcase.assertEqual(self.output, out.getvalue())
            return ret

        return f


from django.test import TestCase
from django.test.utils import override_settings
from django.core import management
from django.contrib.auth.models import User

from docbow_project.docbow.models import FileType, MailingList, Document

EXPEDITION_EMAIL = 'expedition@example.com'
RECIPIENT_EMAIL = 'recipient@example.com'
PRIVATE_RECIPIENT_EMAIL = 'recipient-private@example.com'


class MessageFile(object):
    def __init__(self, filetype, to_addr, from_addr, content, attached_files, headers={}):
        self.filetype = filetype
        self.to_addr = to_addr
        self.from_addr = from_addr
        self.content = content
        self.attached_files = attached_files
        self.headers = headers
        self.message_file = tempfile.NamedTemporaryFile()

    def __enter__(self):
        from email import encoders
        from email.header import Header
        from email.mime.base import MIMEBase
        from email.mime.multipart import MIMEMultipart
        from email.mime.text import MIMEText
        import random

        message = MIMEMultipart()
        message['Subject'] = Header(force_text(self.filetype), 'utf-8')
        message['To'] = Header(self.to_addr, 'utf-8')
        message['From'] = Header(self.from_addr, 'utf-8')
        message['Message-ID'] = '<%s@example.com>' % random.random()
        for key, value in self.headers.items():
            message[key] = value
        msg = MIMEText(self.content, _subtype='plain')
        message.attach(msg)
        for filename, content in self.attached_files:
            msg = MIMEBase('application', 'octet-stream')
            msg.set_payload(force_bytes(content))
            msg.add_header('Content-Disposition', 'attachment', filename=filename)
            encoders.encode_base64(msg)
            message.attach(msg)
        self.message_file.write(force_bytes(message.as_string()))
        self.message_file.flush()
        return self.message_file

    def __exit__(self, *args, **kwargs):
        self.message_file.close()


@override_settings(JOURNAL_DB_FOR_ERROR_ALIAS=None)
@override_settings(MEDIA_ROOT=MEDIA_ROOT)
class SendMailAttachedFileTestCase(TestCase):
    def setUp(self):
        self.pjd_filetype = FileType.objects.create(name='PJD', id=2)
        self.expedition_user = User.objects.create(username='expedition', id=1)
        self.to_user = User.objects.create(username='recipient', email=RECIPIENT_EMAIL, id=2)
        self.to_list = MailingList.objects.create(name='ma liste')
        self.to_list.members.add(self.to_user)

    @stderr_output('')
    def test_attached_file_with_forced_sender(self):
        with MessageFile(
            self.pjd_filetype,
            'whatthefuck@example.com',
            'whatthefuck-too@example.com',
            'coucou',
            (('attached-file', 'content'),),
        ) as f:
            management.call_command(
                'sendmail', RECIPIENT_EMAIL, file=f.name, sender=self.expedition_user.username
            )
            self.assertEqual(Document.objects.count(), 1)
            document = Document.objects.get()
            assert document.comment == 'coucou'
            assert document.attached_files.count() == 1
            assert document.attached_files.get().name == 'attached-file'
            assert document.attached_files.get().content.read() == b'content'
            assert document.to_user.count() == 1
            assert document.to_list.count() == 0
            assert document.to_user.get() == self.to_user

    @stderr_output('')
    def test_attached_file_with_forced_sender_and_private_header(self):
        with MessageFile(
            self.pjd_filetype,
            'whatthefuck@example.com',
            'whatthefuck-too@example.com',
            'coucou',
            (('attached-file', 'content'),),
            headers={'Private': '1'},
        ) as f:
            management.call_command(
                'sendmail', RECIPIENT_EMAIL, file=f.name, sender=self.expedition_user.username
            )
            self.assertEqual(Document.objects.count(), 1)
            document = Document.objects.get()
            assert document.private is True
            assert document.comment == 'coucou'
            assert document.attached_files.count() == 1
            assert document.attached_files.get().name == 'attached-file'
            assert document.attached_files.get().content.read() == b'content'
            assert document.to_user.count() == 1
            assert document.to_list.count() == 0
            assert document.to_user.get() == self.to_user

    @stderr_output('')
    def test_attached_file_with_forced_sender_and_private_email(self):
        with MessageFile(
            self.pjd_filetype,
            'whatthefuck@example.com',
            'whatthefuck-too@example.com',
            'coucou',
            (('attached-file', 'content'),),
        ) as f:
            management.call_command(
                'sendmail', PRIVATE_RECIPIENT_EMAIL, file=f.name, sender=self.expedition_user.username
            )
            self.assertEqual(Document.objects.count(), 1)
            document = Document.objects.get()
            assert document.private is True
            assert document.comment == 'coucou'
            assert document.attached_files.count() == 1
            assert document.attached_files.get().name == 'attached-file'
            assert document.attached_files.get().content.read() == b'content'
            assert document.to_user.count() == 1
            assert document.to_list.count() == 0
            assert document.to_user.get() == self.to_user


def test_email_wrong_encoding(db, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    expedition_user = User.objects.create(username='expedition', id=1)
    User.objects.create(username='recipient', email=RECIPIENT_EMAIL, id=2)
    FileType.objects.create(name='QE-Question', id=2)
    management.call_command(
        'sendmail',
        RECIPIENT_EMAIL,
        file='tests/data/email-encoded-iso-8859-15-but-says-utf-8',
        sender=expedition_user.username,
    )
    assert Document.objects.count() == 1
