#!/usr/bin/python

import hashlib
import time
import json
import http.client

__PRAXIS_CONST_DOMAIN_SANDBOX__ = 'gateway.cashier-test.com'
__PRAXIS_CONST_DOMAIN_LIVE__ = 'gateway.praxispay.com'
__PRAXIS_CONST_PATH__ = '/cashier/cashier'
__PRAXIS_CONST_INTENT_AUTHORIZATION__ = 'authorization'
__PRAXIS_CONST_INTENT_PAYMENT__ = 'payment'
__PRAXIS_CONST_INTENT_WITHDRAWAL__ = 'withdrawal'
__PRAXIS_CONST_VERSION__ = '1.3'

__PRAXIS_AUTH_ENVIRONMENT__ = 'sandbox'
__PRAXIS_AUTH_MERCHANT_ID__ = ''
__PRAXIS_AUTH_MERCHANT_SECRET__ = ''
__PRAXIS_AUTH_APPLICATION_KEY__ = ''

def test_cashier_flow():
    if not (__PRAXIS_AUTH_ENVIRONMENT__ and __PRAXIS_AUTH_MERCHANT_ID__ and __PRAXIS_AUTH_MERCHANT_SECRET__ and __PRAXIS_AUTH_APPLICATION_KEY__):
        raise ValueError('Variables must be set: __PRAXIS_AUTH_ENVIRONMENT__, __PRAXIS_AUTH_MERCHANT_ID__, __PRAXIS_AUTH_MERCHANT_SECRET__, __PRAXIS_AUTH_APPLICATION_KEY__')

    timestamp = int(time.time())
    order_id = 'order_' + str(timestamp)

    request_data = {
        'merchant_id': __PRAXIS_AUTH_MERCHANT_ID__,
        'application_key': __PRAXIS_AUTH_APPLICATION_KEY__,
        'intent': __PRAXIS_CONST_INTENT_PAYMENT__,
        'order_id': order_id,
        'gateway': None,
        'cid': 'test-customer-1',
        'country': 'GB',
        'currency': 'USD',
        'amount': None,
        'balance': 10000,
        'locale': 'en-GB',
        'customer_data': __get_test_customer_data__(),
        'validation_url': None,
        'notification_url': 'https://domain.does.not.exist/notification/' + order_id,
        'return_url': 'https://domain.does.not.exist/return/' + order_id,
        'timestamp': timestamp,
        'version': __PRAXIS_CONST_VERSION__
    }

    response = __send_request__(request_data)
    valid_response = __validate_response__(response)

    if valid_response:
        print valid_response['redirect_url']

def __send_request__(request_data):
    signature = (
        request_data['merchant_id'],
        request_data['application_key'],
        str(request_data['timestamp']),
        request_data['intent'],
        request_data['cid'],
        request_data['order_id'],
        __PRAXIS_AUTH_MERCHANT_SECRET__
    )
    signature = ''.join(signature)
    signature = hashlib.sha384(signature).hexdigest()

    request_domain = __PRAXIS_AUTH_ENVIRONMENT__ is 'sandbox' and __PRAXIS_CONST_DOMAIN_SANDBOX__ or __PRAXIS_CONST_DOMAIN_LIVE__
    request_headers = {'Content-type':'application/json; charset=utf-8', 'GT-Authentication': signature}
    request_body = json.dumps(request_data)

    conn = http.client.HTTPSConnection(request_domain, 443)
    conn.request('POST', __PRAXIS_CONST_PATH__, request_body, request_headers)
    
    response = conn.getresponse()
    response_body = response.read()
    conn.close()

    if not response.status is 200:
        raise Exception('HTTP response status 200 expected, {status} received'.format(status=response.status))
    
    return response_body

def __validate_response__(response_body):
    try:
        response_data = json.loads(response_body)
    except Exception as e:
        raise Exception('Invalid string received in response, not a JSON')

    if response_data is None or not response_data.__class__ is dict:
        raise Exception('Invalid JSON format received in response, object expected')
    
    if not response_data.get('status', None) is 0:
        if response_data.get('description', None):
            raise Exception('Error received: {description}'.format(description=response_data.get('description', None)))
        else:
            raise Exception('Expected status:0 in JSON response, {status} received'.format(status=response_data.get('status', None)))
    
    if not response_data.get('redirect_url', None):
        if response_data.get('description', None):
            raise Exception('Error received: {description}'.format(description=response_data.get('description', None)))
        else:
            raise Exception('Expected redirect_url property not received in JSON response')

    return response_data

def __get_test_customer_data__():
    test_customer_data = {
        'email': 'praxistest@nomail.com',
        'country': 'GB',
        'zip': '123456',
        'city': 'Some City',
        'address': 'Some st., 123'
    }

    return test_customer_data



if __name__ == '__main__':
    test_cashier_flow()