'use strict';

var Logger = require('dw/system/Logger');
var logger = Logger.getLogger('Redsys', 'creditCard');

/**
 * handles the payment authorization for each payment instrument
 * @param {dw.order.Order} order - the order object
 * @param {string} orderNumber - The order number for the order
 * @returns {Object} an error object
 */
function handlePayments(order, orderNumber) {
    var Transaction = require('dw/system/Transaction');
    var OrderMgr = require('dw/order/OrderMgr');
    var PaymentMgr = require('dw/order/PaymentMgr');
    var HookMgr = require('dw/system/HookMgr');
    var result = {};

    if (order.totalNetPrice !== 0.00) {
        var paymentInstruments = order.paymentInstruments;

        if (paymentInstruments.length === 0) {
            Transaction.wrap(function () { OrderMgr.failOrder(order, true); });
            result.error = true;
        }

        if (!result.error) {
            for (var i = 0; i < paymentInstruments.length; i++) {
                var paymentInstrument = paymentInstruments[i];
                var paymentProcessor = PaymentMgr
                    .getPaymentMethod(paymentInstrument.paymentMethod)
                    .paymentProcessor;
                var authorizationResult;
                if (paymentProcessor === null) {
                    Transaction.begin();
                    paymentInstrument.paymentTransaction.setTransactionID(orderNumber);
                    Transaction.commit();
                } else {
                    if (HookMgr.hasHook('app.payment.processor.' +
                            paymentProcessor.ID.toLowerCase())) {
                        authorizationResult = HookMgr.callHook(
                            'app.payment.processor.' + paymentProcessor.ID.toLowerCase(),
                            'Authorize',
                            orderNumber,
                            order,
                            paymentInstrument,
                            paymentProcessor
                        );
                    } else {
                        authorizationResult = HookMgr.callHook(
                            'app.payment.processor.default',
                            'Authorize'
                        );
                    }

                    if (authorizationResult.error) {
                        Transaction.wrap(function () { OrderMgr.failOrder(order, true); });
                        result.error = true;
                        break;
                    }

                    result.challenge = authorizationResult.challenge;
                    result.trataPeticionResponse = authorizationResult.trataPeticionResponse;
                }
            }
        }
    }

    return result;
}

/**
 * Attempts to place the order
 * @param {dw.order.Order} order - The order object to be placed
 * @param {Object} fraudDetectionStatus - an Object returned by the fraud detection hook
 * @param {Object} trataPeticionResponse - an Object with payment response
 * @returns {Object} an error object
 */
function placeOrder(order, fraudDetectionStatus, trataPeticionResponse) {
    var Transaction = require('dw/system/Transaction');
    var OrderMgr = require('dw/order/OrderMgr');
    var Status = require('dw/system/Status');
    var Order = require('dw/order/Order');
    var redsysConstants = require('*/cartridge/scripts/constants/redsysConstants');

    var result = { error: false };

    if (fraudDetectionStatus.status === 'flag') {
        order.setConfirmationStatus(Order.CONFIRMATION_STATUS_NOTCONFIRMED);
    } else {
        var redsysHelper = require('*/cartridge/scripts/redsys/helpers/redsysHelper.js');
        var regexpbar = /\//g;
        var regexpplus = /\+/g;

        if (!trataPeticionResponse) {
            result.error = true;
            return result;
        }

        var trataPeticionSignature = trataPeticionResponse.signature;
        if (!trataPeticionResponse.response) {
            result.error = true;
            logger.error('Error in order {0} calling trataPeticion without response: {1}', order.orderNo, JSON.stringify(trataPeticionResponse));
            Transaction.wrap(function () { OrderMgr.failOrder(order, true); });
            return result;
        }

        var dsResponse = trataPeticionResponse.response.Ds_Response;
        var ourSignature =
            redsysHelper.makeParameters(
                null,
                redsysConstants.REDSYS_CREDIT_CARD,
                trataPeticionResponse.response,
                order.orderNo
            ).payload.Ds_Signature.replace(regexpbar, '_').replace(regexpplus, '-');

        if (ourSignature !== trataPeticionSignature || (dsResponse < -1 || dsResponse > 100)) {
            result.error = true;
            logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, dsResponse);
        } else {
            try {
                Transaction.begin();
                var placeOrderStatus = OrderMgr.placeOrder(order);
                if (placeOrderStatus === Status.ERROR) {
                    throw new Error();
                }
                order.setConfirmationStatus(Order.CONFIRMATION_STATUS_CONFIRMED);
                order.setExportStatus(Order.EXPORT_STATUS_READY);
                order.setPaymentStatus(Order.PAYMENT_STATUS_PAID);

                var paymentInstruments = order.getPaymentInstruments();
                paymentInstruments[0].custom.redsysCreditCardPaymentID = order.orderNo;
                paymentInstruments[0].custom.redsysCreditCardPaymentData = JSON.stringify(trataPeticionResponse.response);

                Transaction.commit();
            } catch (e) {
                Transaction.wrap(function () { OrderMgr.failOrder(order, true); });
                result.error = true;
            }
        }
    }

    return result;
}

module.exports = {
    handlePayments: handlePayments,
    placeOrder: placeOrder
};

