# -*- coding: utf-8 -*-

import base64
import os
import pytest

from django.utils.encoding import force_bytes
from quixote import cleanup
from wcs.formdef import FormDef
from wcs.fields import FileField
from wcs.logged_errors import LoggedError
from wcs.mail_templates import MailTemplate
from wcs.workflows import Workflow, SendmailWorkflowStatusItem
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.form import PicklableUpload
from wcs.qommon.ident.password_accounts import PasswordAccount

from utilities import (get_app, login, create_temporary_pub, clean_temporary_pub)


def setup_module(module):
    cleanup()


def teardown_module(module):
    clean_temporary_pub()


@pytest.fixture
def pub(request):
    pub = create_temporary_pub()
    req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
    pub.set_app_dir(req)
    pub._set_request(req)
    pub.cfg['identification'] = {'methods': ['password']}
    pub.write_cfg()
    return pub


@pytest.fixture
def superuser(pub):
    if pub.user_class.select(lambda x: x.name == 'admin'):
        user1 = pub.user_class.select(lambda x: x.name == 'admin')[0]
        user1.is_admin = True
        user1.store()
        return user1

    user1 = pub.user_class(name='admin')
    user1.is_admin = True
    user1.store()

    account1 = PasswordAccount(id='admin')
    account1.set_password('admin')
    account1.user_id = user1.id
    account1.store()

    return user1


@pytest.fixture
def mail_templates_option(pub):
    if not pub.site_options.has_section('options'):
        pub.site_options.add_section('options')
    pub.site_options.set('options', 'mail-templates', 'true')
    with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
        pub.site_options.write(fd)
    return pub


def test_mail_templates_disabled(pub, superuser):
    if not pub.site_options.has_section('options'):
        pub.site_options.add_section('options')
    pub.site_options.set('options', 'mail-templates', 'false')
    with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
        pub.site_options.write(fd)
    app = login(get_app(pub))
    resp = app.get('/backoffice/workflows/')
    assert 'Mail Templates' not in resp


def test_mail_templates_basics(pub, superuser, mail_templates_option):
    app = login(get_app(pub))
    resp = app.get('/backoffice/workflows/')
    assert 'Mail Templates' in resp
    resp = resp.click('Mail Templates')
    assert 'There are no mail templates defined.' in resp

    resp = resp.click('New')
    resp.form['name'] = 'first mail template'
    resp = resp.form.submit('cancel').follow()
    assert 'There are no mail templates defined.' in resp

    resp = resp.click('New')
    resp.form['name'] = 'first mail template'
    resp = resp.form.submit('submit').follow()
    resp.form['subject'] = 'mail subject'
    resp.form['body'] = 'mail body'
    resp = resp.form.submit('submit').follow()

    resp = resp.click('Edit')
    resp.form['subject'] = 'edited mail subject'
    resp.form['body'] = 'edited mail body'
    resp.form['attachments$element0'] = 'plop'
    resp = resp.form.submit('submit').follow()

    resp = resp.click('Edit')
    assert resp.form['subject'].value == 'edited mail subject'
    assert resp.form['body'].value == 'edited mail body'
    assert resp.form['attachments$element0'].value == 'plop'
    resp = resp.form.submit('submit').follow()

    resp = resp.click('Delete')
    resp = resp.form.submit('cancel').follow()
    assert 'first mail template' in resp

    resp = resp.click('Delete')
    resp = resp.form.submit('submit').follow()
    assert 'first mail template' not in resp
    assert 'There are no mail templates defined.' in resp

    resp = resp.click('New')
    resp.form['name'] = 'first mail template'
    resp = resp.form.submit('submit').follow()
    resp.form['subject'] = 'mail subject'
    resp.form['body'] = 'mail body'
    resp = resp.form.submit('submit').follow()

    resp = app.get('/backoffice/workflows/')
    resp = resp.click('Mail Templates')
    assert 'first mail template' in resp


def test_mail_template_in_use(pub, superuser, mail_templates_option):
    Workflow.wipe()
    MailTemplate.wipe()
    workflow = Workflow(name='test workflow')
    st1 = workflow.add_status('Status1')
    item = SendmailWorkflowStatusItem()
    item.to = ['_receiver']
    item.subject = 'Foobar'
    item.body = 'Hello'
    st1.items.append(item)
    item.parent = st1
    workflow.store()

    mail_template = MailTemplate(name='test mail template')
    mail_template.subject = 'test subject'
    mail_template.body = 'test body'
    mail_template.store()
    assert mail_template.is_in_use() is False

    item.mail_template = mail_template.slug
    workflow.store()
    assert mail_template.is_in_use() is True

    # check workflow usage is displayed
    app = login(get_app(pub))
    resp = app.get('/backoffice/workflows/mail-templates/%s/' % mail_template.id)
    assert 'Usage in workflows' in resp.text
    assert 'test workflow' in resp.text
    resp.click('test workflow')  # make sure the link is ok

    resp = resp.click('Delete')
    assert 'still used' in resp.text


def test_admin_workflow_edit(pub, superuser, mail_templates_option):
    Workflow.wipe()
    MailTemplate.wipe()
    mail_template = MailTemplate(name='test mail template')
    mail_template.subject = 'test subject'
    mail_template.body = 'test body'
    mail_template.store()

    workflow = Workflow(name='test mail template')
    st1 = workflow.add_status('Status1')
    item = SendmailWorkflowStatusItem()
    item.to = ['_receiver']
    item.subject = 'Foobar'
    item.body = 'Hello'
    st1.items.append(item)
    item.parent = st1
    workflow.store()

    app = login(get_app(pub))
    resp = app.get('/backoffice/workflows/%s/' % workflow.id)
    resp = resp.click('Status1')
    resp = resp.click('Email')
    resp.form['mail_template'] = 'test-mail-template'
    resp = resp.form.submit('submit')

    workflow = Workflow.get(workflow.id)
    assert workflow.possible_status[0].items[0].mail_template == 'test-mail-template'


def test_workflow_send_mail_template(pub, superuser, mail_templates_option, emails):
    Workflow.wipe()
    MailTemplate.wipe()

    mail_template = MailTemplate(name='test mail template')
    mail_template.subject = 'test subject'
    mail_template.body = 'test body'
    mail_template.store()

    workflow = Workflow(name='test mail template')
    st1 = workflow.add_status('Status1')
    item = SendmailWorkflowStatusItem()
    item.to = 'xyz@localhost'
    item.subject = 'Foobar'
    item.body = 'Hello'
    item.mail_template = mail_template.slug
    st1.items.append(item)
    item.parent = st1
    workflow.store()

    formdef = FormDef()
    formdef.name = 'baz'
    formdef.fields = []
    formdef.store()

    formdata = formdef.data_class()()
    formdata.just_created()
    formdata.store()

    item.perform(formdata)
    pub.get_request().response.process_after_jobs()
    assert emails.count() == 1
    assert emails.get('test subject')['email_rcpt'] == ['xyz@localhost']
    assert b'test body' in base64.decodestring(force_bytes(emails.get('test subject')['msg'].get_payload(0).get_payload()))

    # check nothing is sent and an error is logged if the mail template is
    # missing
    emails.empty()
    LoggedError.wipe()
    MailTemplate.wipe()
    item.perform(formdata)
    pub.get_request().response.process_after_jobs()
    assert emails.count() == 0
    assert LoggedError.count() == 1
    logged_error = LoggedError.select()[0]
    assert logged_error.summary == 'reference to invalid mail template test-mail-template in status Status1'


def test_workflow_send_mail_template_attachments(pub, superuser, mail_templates_option, emails):
    Workflow.wipe()
    MailTemplate.wipe()

    mail_template = MailTemplate(name='test mail template')
    mail_template.subject = 'test subject'
    mail_template.body = 'test body'
    mail_template.attachments = ['form_var_file1_raw']
    mail_template.store()

    workflow = Workflow(name='test mail template')
    st1 = workflow.add_status('Status1')
    item = SendmailWorkflowStatusItem()
    item.to = 'xyz@localhost'
    item.subject = 'Foobar'
    item.body = 'Hello'
    item.mail_template = mail_template.slug
    st1.items.append(item)
    item.parent = st1
    workflow.store()

    formdef = FormDef()
    formdef.name = 'baz'
    formdef.fields = [
        FileField(id='1', label='File', type='file', varname='file1'),
    ]
    formdef.store()

    upload = PicklableUpload('test.jpeg', 'image/jpeg')
    jpg = open(os.path.join(os.path.dirname(__file__), 'image-with-gps-data.jpeg'), 'rb').read()
    upload.receive([jpg])
    formdata = formdef.data_class()()
    formdata.data = {'1': upload}
    formdata.just_created()
    formdata.store()
    pub.substitutions.feed(formdata)

    item.perform(formdata)
    pub.get_request().response.process_after_jobs()
    assert emails.count() == 1
    payloads = emails.get('test subject')['msg'].get_payload()
    assert len(payloads) == 2
    assert payloads[1].get_content_type() == 'image/jpeg'

    # check two files are sent if mail attachments are also defined on the
    # action itself.
    emails.empty()
    item.attachments = ['form_var_file1_raw']
    item.perform(formdata)
    pub.get_request().response.process_after_jobs()
    payloads = emails.get('test subject')['msg'].get_payload()
    assert len(payloads) == 3
    assert payloads[1].get_content_type() == 'image/jpeg'
    assert payloads[2].get_content_type() == 'image/jpeg'
