import requests
import json
import asyncio
import time
import sys
from datetime import datetime
from dateutil.relativedelta import *

# refund must be on the transactionID of the capture
# cancellation on the transactionID before capture
date = datetime.utcnow()
final = date+relativedelta(months=+1)
value = 6 # Value for the checkout
terminalId = 50461 # Place terminalID sent by Onboarding Team
start_date = date.isoformat()[:-3] + 'Z' # Initial date in ISO for MB 
end_date = final.isoformat()[:-3] + 'Z'  # End date in ISO for MB 


""" Configurations and Settings """

base_url = 'https://spg.qly.site1.sibs.pt'

headers = {
    'X-IBM-Client-Id': '4e5840f3-626b-4fcc-8582-050ca943e71e', # Client ID will be sent by Onboarding Team
    'Content-type': 'application/json; charset=utf-8'
}

credentials = {
    # Bearer token will be sent by the Onboarding Team
    'bearer': 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJmYjgwMTg3OS1jZTc2LTQ2YmItOWRiOS03MTY3ZGYxMGQxNjQiLCJleHAiOjAsIm5iZiI6MCwiaWF0IjoxNjE3NzA2NDUyLCJpc3MiOiJodHRwczovL3FseS5zaXRlMi5zc28uc3lzLnNpYnMucHQ6NDQzL2F1dGgvcmVhbG1zL1FMWS5TUEcuQVBJIiwiYXVkIjoiUUxZLlNQRy5BUEktQ0xJIiwic3ViIjoiOWQzMWMwMjctYzFlOC00Y2U5LWFjY2EtMTA0ZWYyODRlMjJhIiwidHlwIjoiT2ZmbGluZSIsImF6cCI6IlFMWS5TUEcuQVBJLUNMSSIsInNlc3Npb25fc3RhdGUiOiJmMDlhNzM0YS02MjJhLTQxZjktYTBiMi0wOGNlM2JjNTdhOTIiLCJjbGllbnRfc2Vzc2lvbiI6ImE2ODUwYzEzLTYxZWQtNDFmNy04OThkLTE1OGQxMDdjYTliYiIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJ2aWV3LXByb2ZpbGUiXX19fQ.I1XkYhgmYq8WpAh6mhs3bCRUoFNnIukWKJHxddMSMbS1ZcpC9Hc6EDfp1CDbF7ocaNfZjuiHZG7L5dGQ8iF9MMLxW8ExsTxaEU6eQ1QBqko5ESx1dTLgmW0-FyrJ_4NjT9HcFMmvFJiuLqKkjhUwSzhPjCTbmIWeNS6dbeTHyoMRSkkC4RSgV_DH7RAo14_gEAlfWujC1GFw3XlfueCowONi6qu6eiX7UMZVcNm5vwjDBHO-gEKoZIEbidvN0PR1F_4p0FGwYP_A82Se7WTy9G3KV6mi5Bhdljvc2p7ZBzANkNflGiXUxlOsQTAyRPw6zo87EoCtTlfBXpw3325dSg.eyJtYyI6Ijk5OTk5OTkiLCJ0YyI6IjUwNDYxIn0=.6245CF49DA98015A6979A76869234EF96FDEAC39F4EDB8998DF6266BE3BB2C40',
    'clientid': '4e5840f3-626b-4fcc-8582-050ca943e71e',
}

# AUTH for Multibanco means reference generation
# For MB Way you must use PURS
params = {
    'checkout': {
        'merchant': {
            'terminalId': terminalId,
            'channel': 'web',
            'merchantTransactionId': '5351136' # Use a number for your system
        },
        'transaction': {
            'transactionTimestamp': start_date,
            'description': 'Transaction short description',
            'moto': False,
            'paymentType': 'AUTH', # AUTH or PURS
            'amount': {
                'value': value,
                'currency': 'EUR'
            },
            'paymentMethod': [
                'REFERENCE',
                'CARD',
                'MBWAY'
            ],
            'paymentReference': {
                'initialDatetime': start_date,
                'finalDatetime': end_date,
                'maxAmount': {
                    'value': value,
                    'currency': 'EUR'
                },
                'minAmount': {
                    'value': value,
                    'currency': 'EUR'
                },
                'entity': '24000' # In the future your REF MB entity, for tests use this
            }
        }
    },
    'Backoffice': {
        'merchant': {
            'terminalId': terminalId,
            'channel': 'web',
            'merchantTransactionId': '5351136' # Use a number for your system
        },
        'transaction': {
            'transactionTimestamp': end_date,
            'description': 'Transaction short description',
            'amount': {
                'value': value,
                'currency': 'EUR'
            },
            'originalTransaction': {
                'id': '',
                'datetime': end_date
            }
        }
    },
    'MBWay': {
        'customerPhone': '351#969770085' # Client MB Way alias
    }
}

def request_post(url, data):
    try:
        r = requests.post(url, data=data, headers=headers)
        return r
    except Exception as e:
        print('Error sending POST request', e)
        return e


def print_pretty(s):
    print(json.dumps(s, indent=4))

""" Checkout """
def checkout():
    try:
        checkout_request = params['checkout']
        headers['Authorization'] = credentials['bearer']

        url = base_url + '/api/v1/payments'

        ### Error checks ###

        # Transaction time check
        transaction = checkout_request['transaction']
        transactionTimestamp = datetime.strptime(transaction['transactionTimestamp'], '%Y-%m-%dT%H:%M:%S.%fZ')
        initialDatetime = datetime.strptime(transaction['paymentReference']['initialDatetime'], '%Y-%m-%dT%H:%M:%S.%fZ')
        finalDatetime = datetime.strptime(transaction['paymentReference']['finalDatetime'], '%Y-%m-%dT%H:%M:%S.%fZ')

        if not(transactionTimestamp >= initialDatetime):
            raise Exception('Verify if "transactionTimestamp" is greater than "finalDatetime"')
        if initialDatetime > finalDatetime:
            raise Exception('Verify if "finalDatetime" is greater than "initialDatetime"')

        # Verify payment type
        if transaction['paymentType'] != 'PURS' and transaction['paymentType'] != 'AUTH':
            print(transaction['paymentType'])
            raise Exception('Verify if "paymentType" is "PURS" or "AUTH"')

        checkout_request = json.dumps(checkout_request)
        r = request_post(url, checkout_request)

        if r.status_code != 200:
            raise Exception(r.text)

        response = json.loads(r.text)
        print_pretty(response)

        credentials['signature'] = 'Digest ' + response['transactionSignature']

        return response

    except Exception as e:
        print('Error at Checkout:', e)
        return e


def cancellation(c):
    try:
        if 'Backoffice' in params:
            cancellation_request = params['Backoffice']

        headers['Authorization'] = credentials['bearer']
        cancellation_request['transaction']['originalTransaction']['id'] = c['transactionID']
        url = base_url + '/api/v1/payments/' + c['transactionID'] + '/cancellation'

        cancellation_request = json.dumps(cancellation_request)
        r = request_post(url, cancellation_request)

        response = json.loads(r.text)
        print_pretty(response)

        return response['transactionID']

    except Exception as e:
        print('Error at Cancellation', e)
        return e

def refund(c):
    try:
        if 'Backoffice' in params:
            refund_request = params['Backoffice']

        headers['Authorization'] = credentials['bearer']
        refund_request['transaction']['originalTransaction']['id'] = c['transactionID']
        url = base_url + '/api/v1/payments/' + c['transactionID'] + '/refund'

        # Verify payment type
        transaction = params['checkout']['transaction']

        refund_request = json.dumps(refund_request)
        r = request_post(url, refund_request)

        response = json.loads(r.text)
        print_pretty(response)

    except Exception as e:
        print('Error at Refund', e)

def mbwayid(c):
    try:
        time.sleep(1)
        headers['Authorization'] = credentials['signature']
        transactionID = c['transactionID']

        url = base_url + '/api/v1/payments/' + transactionID + '/mbway-id/purchase'

        if 'MBWay' in params:
            mbway_request = params['MBWay']
        
        mbway_request = json.dumps(mbway_request)
        r = request_post(url, mbway_request)

        response = json.loads(r.text)
        print_pretty(response)

        if r.status_code != 200:
            raise Exception(r.text)

    except Exception as e:
        print('Error at MBWayID:', e)
        return e

def mbreference(c):
    try:
        headers['Authorization'] = credentials['signature']
        transactionID = c['transactionID']
        url = base_url + '/api/v1/payments/' + transactionID + '/service-reference/generate'

        r = requests.post(url, data={}, headers=headers)

        response = json.loads(r.text)
        print_pretty(response)

    except Exception as e:
        print('Error at MB Reference', e)





print ('-'*80)
c = checkout()
if isinstance(c, Exception):
    sys.exit()

isExit = False
while not isExit:
    print ('-'*80)
    print("""
    # W - MBWAY ID
    # M - MB Reference
    # R - Refund
    # X - Cancellation (Only MB Reference)
    # Q - Quit
    """)

    val = input("Select your option: ")
    if not val in 'WMXRQwmxrq':
        print(f'Option {val} is not valid.')
        continue
    elif val in 'Ww':
        mbwayid(c)
    elif val in 'Rr':
        refund(c)
    elif val in 'Xx':
        cancellation(c)
    elif val in 'Mm':
        mbreference(c)
    elif val in 'Qq':
        print ('-'*80)
        sys.exit()


    

