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

# Copyright 2019 Open End AB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
if (sys.version_info >=(3, 0)):
    PYT3 = True
    import urllib.request
    import urllib.parse
else:
    PYT3 = False
    import urllib2
    import urlparse

import contextlib
import json
import os
import py
import subprocess
import time
import uuid

from . import support

here = os.path.dirname(__file__)


class Container(object):
    def __init__(self, **kw):
        self.__dict__.update(kw)


def do_purchase(products, emailaddress):
    params = {
        'data': [
            {'items': [{'product': product} for product in products],
             'buyerName': 'Kalle Anka',
             'buyerEmail': emailaddress}
        ]
    }

    if PYT3:
        req = urllib.request.Request(urllib.parse.urljoin(support.url, '/rest/purchase'),
                                  json.dumps(params).encode('ascii'),
                                     {'Content-Type': 'application/json'})
        data = json.load(urllib.request.urlopen(req))
    else:
        req = urllib2.Request(urlparse.urljoin(support.url, '/rest/purchase'),
                                  json.dumps(params),
                                  {'Content-Type': 'application/json'})
        data = json.load(urllib2.urlopen(req))

    return Container(id=data['purchase'],
                     invoice=data['invoiceUrl'],
                     buyerEmail=emailaddress)


def check_mail(client, mailssh, purchase, mailtype):
    client.run('sendmail -qf')
    message, = mailssh.find_and_delete_mail(None, 'TO', purchase.buyerEmail)
    msg, headers = mailssh.parse(message)
    assert headers['X-OE-MailType'] == [mailtype]
    assert purchase.invoice in msg
    return msg, headers


@contextlib.contextmanager
def check_mails(client, mailssh, purchase):
    check_mail(client, mailssh, purchase, 'order-confirmation')
    yield
    check_mail(client, mailssh, purchase, 'full-payment-confirmation')


def gen_pg(client, org, id_args=[1, 1]):
    cmd = 'python /root/accounting/members/paymentgen.py %s %s %s' % (
        org.id, id_args[0], id_args[1])
    id_args[0] += 1
    id_args[1] += 1000
    stdin, stdout, stderr = client.exec_command('PYTHONPATH=/root/accounting ' +
                                                cmd)
    return stdout.read()


def upload_pg(tmpdir, ssh, pgdata):
    pgfile = tmpdir.join('pgfile')
    pgfile.write(pgdata)

    dest = uuid.uuid4()
    with ssh(username='nordea') as client:
        sftp = client.open_sftp()
        sftp.put(str(pgfile), 'incoming/%s' % dest, confirm=False)


@py.test.mark.usefixtures('cluster', 'clean_db', 'bootstrapped', 'mailssh',
                          'ssh', 'org', 'emailaddress')
def test_full_plusgiro_payment(mailssh, ssh, org, emailaddress, tmpdir):
    purchase = do_purchase([org.product], emailaddress)
    with ssh() as client:
        with check_mails(client, mailssh, purchase):
            pgdata = gen_pg(client, org)
            upload_pg(tmpdir, ssh, pgdata)


@py.test.mark.usefixtures('cluster', 'clean_db', 'bootstrapped', 'mailssh',
                          'ssh', 'org', 'emailaddress')
def test_partial_plusgiro_payment(ssh, mailssh, org, emailaddress,
                                  tmpdir):
    purchase = do_purchase([org.product], emailaddress)

    with ssh() as client:
        with check_mails(client, mailssh, purchase):
            pgdata1 = gen_pg(client, org)
            pgdata2 = gen_pg(client, org)
            pgdata3 = gen_pg(client, org)
            # The sum is 66666 (öre). It is probably unique in the fake pgfile,
            # so we can simply replace it in order to make partial payments.
            if PYT3:
                partial_payment1 = pgdata1.replace(b'66666', b'22222')  # pay 222.22 SEK
                partial_payment2 = pgdata2.replace(b'66666', b'33333')  # pay 333.33 SEK
                final_payment = pgdata3.replace(b'66666', b'11111')  # final 111.11 SEK
            else:
                partial_payment1 = pgdata1.replace('66666', '22222')  # pay 222.22 SEK
                partial_payment2 = pgdata2.replace('66666', '33333')  # pay 333.33 SEK
                final_payment = pgdata3.replace('66666', '11111')  # final 111.11 SEK

            upload_pg(tmpdir, ssh, partial_payment1)
            msg, headers = check_mail(client, mailssh, purchase,
                                      'partial-payment-confirmation')
            assert '222,22' in msg  # amount paid
            assert '444,44' in msg  # amount remaining

            upload_pg(tmpdir, ssh, partial_payment2)
            msg, headers = check_mail(client, mailssh, purchase,
                                      'partial-payment-confirmation')
            assert '333,33' in msg  # amount paid
            assert '111,11' in msg  # amount remaining

            upload_pg(tmpdir, ssh, final_payment)


@py.test.mark.usefixtures('cluster', 'clean_db', 'bootstrapped', 'mailssh',
                          'nodes', 'ssh', 'org', 'emailaddress')
def test_swish_payment(nodes, ssh, mailssh, org, emailaddress):
    #py.test.skip('Skip swish tests until certificates work')
    purchase = do_purchase([org.product], emailaddress)
    with ssh() as client:
        with check_mails(client, mailssh, purchase):
            print(purchase.invoice)
            if PYT3:
                parsed = urllib.parse.urlparse(purchase.invoice)
                _, _, purchase, _ = parsed.path.split('/')
                path = '/providers/swish/charge/%s/%s' % (org.swish_provider, purchase)
                url = urllib.parse.urlunparse((parsed.scheme, parsed.netloc, path,
                                       '', '', ''))
                data = {'phone': '1231181189'}
                req = urllib.request.Request(url, json.dumps(data).encode('ascii'),
                                      {'Content-Type': 'application/json'})
                response = json.load(urllib.request.urlopen(req))
            else:
                parsed = urlparse.urlparse(purchase.invoice)
                _, _, purchase, _ = parsed.path.split('/')
                path = '/providers/swish/charge/%s/%s' % (org.swish_provider, purchase)
                url = urlparse.urlunparse((parsed.scheme, parsed.netloc, path,
                                           '', '', ''))
                data = {'phone': '1231181189'}
                req = urllib2.Request(url, json.dumps(data),
                                      {'Content-Type': 'application/json'})
                response = json.load(urllib2.urlopen(req))
            print(response)
            assert response['status'] == 'CREATED'

            path = '/providers/swish/poll/%s/%s' % (org.swish_provider,
                                                    response['id'])
            if PYT3:
                url = urllib.parse.urlunparse((parsed.scheme, parsed.netloc, path,
                                               '', '', ''))
            else:
                url = urlparse.urlunparse((parsed.scheme, parsed.netloc, path,
                                           '', '', ''))

            for _ in range(20):
                if PYT3:
                    req = urllib.request.Request(url)
                    response = json.load(urllib.request.urlopen(req))
                else:
                    req = urllib2.Request(url)
                    response = json.load(urllib2.urlopen(req))

                print(response)
                if response['status'] == 'PAID':
                    break
                time.sleep(1)

[((37, 7, 37, 32), 'os.path.dirname', 'os.path.dirname', ({(37, 23, 37, 31): '__file__'}, {}), '(__file__)', False, 'import os\n'), ((106, 1, 107, 55), 'py.test.mark.usefixtures', 'py.test.mark.usefixtures', ({(106, 26, 106, 35): '"""cluster"""', (106, 37, 106, 47): '"""clean_db"""', (106, 49, 106, 63): '"""bootstrapped"""', (106, 65, 106, 74): '"""mailssh"""', (107, 26, 107, 31): '"""ssh"""', (107, 33, 107, 38): '"""org"""', (107, 40, 107, 54): '"""emailaddress"""'}, {}), "('cluster', 'clean_db', 'bootstrapped', 'mailssh',\n    'ssh', 'org', 'emailaddress')", False, 'import py\n'), ((116, 1, 117, 55), 'py.test.mark.usefixtures', 'py.test.mark.usefixtures', ({(116, 26, 116, 35): '"""cluster"""', (116, 37, 116, 47): '"""clean_db"""', (116, 49, 116, 63): '"""bootstrapped"""', (116, 65, 116, 74): '"""mailssh"""', (117, 26, 117, 31): '"""ssh"""', (117, 33, 117, 38): '"""org"""', (117, 40, 117, 54): '"""emailaddress"""'}, {}), "('cluster', 'clean_db', 'bootstrapped', 'mailssh',\n    'ssh', 'org', 'emailaddress')", False, 'import py\n'), ((153, 1, 154, 64), 'py.test.mark.usefixtures', 'py.test.mark.usefixtures', ({(153, 26, 153, 35): '"""cluster"""', (153, 37, 153, 47): '"""clean_db"""', (153, 49, 153, 63): '"""bootstrapped"""', (153, 65, 153, 74): '"""mailssh"""', (154, 26, 154, 33): '"""nodes"""', (154, 35, 154, 40): '"""ssh"""', (154, 42, 154, 47): '"""org"""', (154, 49, 154, 63): '"""emailaddress"""'}, {}), "('cluster', 'clean_db', 'bootstrapped', 'mailssh',\n    'nodes', 'ssh', 'org', 'emailaddress')", False, 'import py\n'), ((100, 11, 100, 23), 'uuid.uuid4', 'uuid.uuid4', ({}, {}), '()', False, 'import uuid\n'), ((60, 30, 60, 77), 'urlparse.urljoin', 'urlparse.urljoin', ({(60, 47, 60, 58): 'support.url', (60, 60, 60, 76): '"""/rest/purchase"""'}, {}), "(support.url, '/rest/purchase')", False, 'import urlparse\n'), ((61, 34, 61, 52), 'json.dumps', 'json.dumps', ({(61, 45, 61, 51): 'params'}, {}), '(params)', False, 'import json\n'), ((63, 25, 63, 45), 'urllib2.urlopen', 'urllib2.urlopen', ({(63, 41, 63, 44): 'req'}, {}), '(req)', False, 'import urllib2\n'), ((172, 25, 172, 60), 'urlparse.urlparse', 'urlparse.urlparse', ({(172, 43, 172, 59): 'purchase.invoice'}, {}), '(purchase.invoice)', False, 'import urlparse\n'), ((175, 22, 176, 55), 'urlparse.urlunparse', 'urlparse.urlunparse', ({(175, 42, 176, 54): "(parsed.scheme, parsed.netloc, path, '', '', '')"}, {}), "((parsed.scheme, parsed.netloc, path, '', '', ''))", False, 'import urlparse\n'), ((190, 22, 191, 55), 'urlparse.urlunparse', 'urlparse.urlunparse', ({(190, 42, 191, 54): "(parsed.scheme, parsed.netloc, path, '', '', '')"}, {}), "((parsed.scheme, parsed.netloc, path, '', '', ''))", False, 'import urlparse\n'), ((204, 16, 204, 29), 'time.sleep', 'time.sleep', ({(204, 27, 204, 28): '(1)'}, {}), '(1)', False, 'import time\n'), ((56, 34, 56, 52), 'json.dumps', 'json.dumps', ({(56, 45, 56, 51): 'params'}, {}), '(params)', False, 'import json\n'), ((178, 43, 178, 59), 'json.dumps', 'json.dumps', ({(178, 54, 178, 58): 'data'}, {}), '(data)', False, 'import json\n'), ((180, 37, 180, 57), 'urllib2.urlopen', 'urllib2.urlopen', ({(180, 53, 180, 56): 'req'}, {}), '(req)', False, 'import urllib2\n'), ((198, 26, 198, 46), 'urllib2.Request', 'urllib2.Request', ({(198, 42, 198, 45): 'url'}, {}), '(url)', False, 'import urllib2\n'), ((199, 41, 199, 61), 'urllib2.urlopen', 'urllib2.urlopen', ({(199, 57, 199, 60): 'req'}, {}), '(req)', False, 'import urllib2\n'), ((168, 50, 168, 66), 'json.dumps', 'json.dumps', ({(168, 61, 168, 65): 'data'}, {}), '(data)', False, 'import json\n')]