/* @flow */

import { logger, FPTI_KEY } from 'paypal-braintree-web-client/src';
import { ZalgoPromise } from 'zalgo-promise/src';
import { on, send } from 'post-robot/src';
import { getAncestor, isSameDomain, isFileProtocol } from 'cross-domain-utils/src';
import { memoize, request, base64encode } from 'belter/src';

import { URLS, DOMAINS } from '../config';
import { FPTI_STATE, FPTI_CONTEXT_TYPE, FPTI_TRANSITION } from '../constants';
import { isPayPalDomain } from '../lib';

type ProxyRest = {
    [string] : (...args : Array<mixed>) => ZalgoPromise<*>
};

let proxyRest : ProxyRest = {};

export let createAccessToken = memoize((clientID : string) : ZalgoPromise<string> => {

    logger.info(`rest_api_create_access_token`);

    if (proxyRest.createAccessToken && !proxyRest.createAccessToken.source.closed) {
        return proxyRest.createAccessToken(clientID);
    }

    let basicAuth : string = base64encode(`${ clientID }:`);

    return request({

        method:  `post`,
        url:     URLS.AUTH,
        headers: {
            Authorization: `Basic ${ basicAuth }`
        },
        data: {
            grant_type: `client_credentials`
        }

    }).then(res => {

        if (res && res.error === 'invalid_client') {
            throw new Error(`Auth Api invalid client id: ${ clientID }:\n\n${ JSON.stringify(res, null, 4) }`);
        }

        if (!res || !res.access_token) {
            throw new Error(`Auth Api response error:\n\n${ JSON.stringify(res, null, 4) }`);
        }

        return res.access_token;
    });

}, { time: 10 * 60 * 1000 });

function logOrderResponse(orderID) {
    logger.track({
        [ FPTI_KEY.STATE ]:        FPTI_STATE.BUTTON,
        [ FPTI_KEY.TRANSITION ]:   FPTI_TRANSITION.CREATE_PAYMENT,
        [ FPTI_KEY.CONTEXT_TYPE ]: FPTI_CONTEXT_TYPE.EC_TOKEN,
        [ FPTI_KEY.TOKEN ]:        orderID,
        [ FPTI_KEY.CONTEXT_ID ]:   orderID
    });
}

function getDefaultReturnUrl() : string {
    return isFileProtocol()
        ? `https://www.paypal.com`
        : `${ window.location.protocol }//${ window.location.host }`;
}

export function createOrder(clientID : string, orderDetails : Object) : ZalgoPromise<string> {

    logger.info(`rest_api_create_order_token`);

    if (!clientID) {
        throw new Error(`Client ID not passed`);
    }

    if (proxyRest.createOrder && !proxyRest.createOrder.source.closed) {
        return proxyRest.createOrder(clientID, orderDetails);
    }

    let { order, meta } = orderDetails;

    if (!order) {
        throw new Error(`Expected order details to be passed`);
    }

    order = { ...order };
    order.intent = order.intent || 'CAPTURE';
    order.application_context = order.application_context || {};
    order.application_context.return_url = order.application_context.return_url || getDefaultReturnUrl();
    order.application_context.cancel_url = order.application_context.cancel_url || getDefaultReturnUrl();
    order.purchase_units = order.purchase_units || [];
    order.purchase_units[0] = order.purchase_units[0] || {};
    order.purchase_units.forEach(unit => {
        unit.reference_id = unit.reference_id || Math.random().toString();
    });

    return createAccessToken(clientID).then((accessToken) : ZalgoPromise<Object> => {

        let headers : Object = {
            Authorization: `Bearer ${ accessToken }`
        };

        if (meta && meta.partner_attribution_id) {
            headers['PayPal-Partner-Attribution-Id'] = meta.partner_attribution_id;
        }

        return request({
            method: `post`,
            url:    URLS.ORDER,
            headers,
            json:   order
        });

    }).then((res) : string => {

        logOrderResponse(res.id);

        if (res && res.id) {
            return res.id;
        }

        throw new Error(`Payment Api response error:\n\n${ JSON.stringify(res, null, 4) }`);
    });
}

const PROXY_REST = `proxy_rest`;
let parentWin = getAncestor();

on(PROXY_REST, { domain: DOMAINS.PAYPAL }, ({ data }) => {
    proxyRest = data;
});

if (parentWin && isPayPalDomain() && !isSameDomain(parentWin)) {
    send(parentWin, PROXY_REST, { createAccessToken, createOrder })
        .catch(() => {
            // pass
        });
}

@@ -1177,19 +1177,26 @@
 %7D).then(
-res
+(%7B body %7D)
  =%3E %7B%0A%0A 
@@ -1206,26 +1206,28 @@
     if (
-res && res
+body && body
 .error =
@@ -1334,35 +1334,36 @@
  JSON.stringify(
-res
+body
 , null, 4) %7D%60);%0A
@@ -1390,19 +1390,21 @@
 f (!
-res
+body
  %7C%7C !
-res
+body
 .acc
@@ -1483,35 +1483,36 @@
  JSON.stringify(
-res
+body
 , null, 4) %7D%60);%0A
@@ -1537,19 +1537,20 @@
  return 
-res
+body
 .access_
@@ -3687,19 +3687,24 @@
 ).then((
-res
+%7B body %7D
 ) : stri
@@ -3737,19 +3737,20 @@
 esponse(
-res
+body
 .id);%0A%0A 
@@ -3764,18 +3764,20 @@
 if (
-res && res
+body && body
 .id)
@@ -3798,19 +3798,20 @@
  return 
-res
+body
 .id;%0A   
@@ -3892,19 +3892,20 @@
 ringify(
-res
+body
 , null, 

Use body from http response