'use strict';

var redsysConstants = require('*/cartridge/scripts/constants/redsysConstants');
var redsysHelper = require('*/cartridge/scripts/redsys/helpers/redsysHelper.js');
var redsysService = require('*/cartridge/scripts/services/redsysRest');
var Logger = require('dw/system/Logger');
var logger = Logger.getLogger('Redsys', 'rest');

/**
 * Request to get credit card version to use the proper protocol
 * @param {dw.order.Order} order - Customers's order
 * @return {Object/boolean} returns an error object / false
 */
function iniciaPeticion(order) {
    var amount = redsysHelper.calculateAmount(order.paymentTransaction.amount.value);
    var status = redsysConstants.REDSYS_RESPONSE_FAIL;
    var srvResponse = null;
    var decodedResponse = null;
    var iniciaPeticionResponse = null;

    if (!order) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Order not exist');
    }
    var config = redsysHelper.getRedsysIniciaPeticionConfig(order.orderNo, amount);
    if (config.error) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
    }

    var params = redsysHelper.makeParameters(
        redsysConstants.REDSYS_SERVICE_INICIA_PETICION_REST,
        order.paymentInstrument.paymentMethod,
        config,
        order.orderNo
    );

    try {
        srvResponse = redsysService.createHttpService.call(params);
    } catch (e) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling Redsys service: {0}}', e.message);
    }

    if (srvResponse.isOk()) {
        decodedResponse = redsysHelper.decodeResponse(srvResponse);
        if (decodedResponse.error) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error calling iniciaPeticion: {0}', decodedResponse.message);
        } else {
            iniciaPeticionResponse = decodedResponse;
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }
    }

    if (srvResponse.errorMessage) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling iniciaPeticion: {0}', decodedResponse.message);
    }

    return { status: status, response: iniciaPeticionResponse };
}

/**
 * Request to get credit card version to use the proper protocol
 * @param {dbject} iniciaPeticionResponse - Customers's order
 * @param {dw.order.Order} order - Customers's order
 * @return {Object} returns an error object
 */
function trataPeticion(iniciaPeticionResponse, order) {
    var amount = redsysHelper.calculateAmount(order.paymentTransaction.amount.value);
    var status = redsysConstants.REDSYS_RESPONSE_FAIL;
    var typeOfResponse = redsysConstants.REDSYS_FRICTIONLESS;
    var threeDSMethodURL = null;
    var srvResponse = null;
    var decodedResponse = null;
    var trataPeticionResponse = null;
    var signature = null;

    if (!iniciaPeticionResponse) {
        return false;
    }

    var config = redsysHelper.getRedsysTrataPeticionConfig(iniciaPeticionResponse, order.orderNo, amount);
    if (config.error) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
    }

    var params = redsysHelper.makeParameters(
        redsysConstants.REDSYS_SERVICE_TRATA_PETICION_REST,
        order.paymentInstrument.paymentMethod,
        config,
        order.orderNo
    );

    try {
        srvResponse = redsysService.createHttpService.call(params);
    } catch (e) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling Redsys service: {0}}', e.message);
    }

    if (srvResponse.isOk()) {
        decodedResponse = redsysHelper.decodeResponse(srvResponse);
        signature = JSON.parse(srvResponse.object).Ds_Signature;
        if (decodedResponse.error) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, decodedResponse.message);
        }

        // Ds_Response codes from 0000 a 0099 authorizes the transaction
        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response < 100) {
            trataPeticionResponse = decodedResponse;
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }

        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response > 100) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, decodedResponse.Ds_Response);
        }

        if (decodedResponse.Ds_EMV3DS && decodedResponse.Ds_EMV3DS.threeDSInfo === redsysConstants.REDSYS_EMV3DS_CHALLENGE_REQUEST) {
            trataPeticionResponse = decodedResponse;
            status = redsysConstants.REDSYS_RESPONSE_PASS;
            typeOfResponse = redsysConstants.REDSYS_EMV3DS_CHALLENGE_REQUEST;
            threeDSMethodURL = iniciaPeticionResponse.Ds_EMV3DS.threeDSMethodURL ? 'Y' : 'N';
        }
    }

    if (srvResponse.errorMessage) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, decodedResponse.message);
    }

    return { status: status, typeOfResponse: typeOfResponse, threeDSMethodURL: threeDSMethodURL, response: trataPeticionResponse, signature: signature };
}

/**
 * Request to authenticate with challenge
 * @param {dw.order.Order} orderNo - Customers's order number
 * @param {string} authData - Authentication data
 * @return {Object} returns an error object
 */
function autenticacion(orderNo, authData) {
    var config = redsysHelper.getRedsysAutenticacionConfig(orderNo, authData);
    var status = redsysConstants.REDSYS_RESPONSE_FAIL;
    var srvResponse = null;
    var decodedResponse = null;
    var signature = null;

    if (config.error) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
    }

    var params = redsysHelper.makeParameters(
        redsysConstants.REDSYS_SERVICE_TRATA_PETICION_REST,
        redsysConstants.REDSYS_CREDIT_CARD,
        config,
        orderNo
    );

    try {
        srvResponse = redsysService.createHttpService.call(params);
    } catch (e) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling Redsys service: {0}}', e.message);
    }

    if (srvResponse.isOk()) {
        decodedResponse = redsysHelper.decodeResponse(srvResponse);
        signature = JSON.parse(srvResponse.object).Ds_Signature;
        if (decodedResponse.error) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error in order {0} calling trataPeticion: {1}', orderNo, decodedResponse.message);
        }

        // Ds_Response codes from 0000 a 0099 authorizes the transaction
        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response < 100) {
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }

        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response > 100) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error in order {0} calling trataPeticion with error code: {1}', orderNo, decodedResponse.Ds_Response);
        }

        if (decodedResponse.Ds_EMV3DS && decodedResponse.Ds_EMV3DS.threeDSInfo === redsysConstants.REDSYS_EMV3DS_CHALLENGE_REQUEST) {
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }
    }

    if (srvResponse.errorMessage) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling iniciaPeticion: {0}', decodedResponse.message);
    }

    return { status: status, response: decodedResponse, signature: signature };
}

/**
 * Delete saved payment in Redsys for this credit card
 * @param {string} paymentUUID - Payment UUID
 * @param {string} token - Payment token
 * @return {JSON} returns status and service response
 */
function borraPreferencia(paymentUUID, token) {
    var decodedResponse = null;
    var status = redsysConstants.REDSYS_RESPONSE_FAIL;
    var srvResponse = null;

    /**
     * Redsys needs a value in orderId param to work, can be any number.
     * That number doesn't have any relation with customer orders
     * We use 12 first numbers of payment.UUID
     */
    var UUIDWithoutCharacters = paymentUUID.replace(/[^\d]/g, '');
    var orderID = UUIDWithoutCharacters.slice(0, 12);
    var config = redsysHelper.getRedsysBorraPreferenciaConfig(paymentUUID, token, orderID);

    if (config.error) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
    }

    var params = redsysHelper.makeParameters(
        redsysConstants.REDSYS_SERVICE_TRATA_PETICION_REST,
        redsysConstants.REDSYS_CREDIT_CARD,
        config,
        orderID
    );

    try {
        srvResponse = redsysService.createHttpService.call(params);
    } catch (e) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling Redsys service to delete a credit card with UUID: {0} and error: {0}}', paymentUUID, e.message);
    }

    if (srvResponse.isOk()) {
        decodedResponse = redsysHelper.decodeResponse(srvResponse);
        if (decodedResponse.error) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error calling borraPreferencia: {0}', decodedResponse.message);
        }

        // Ds_Response codes from 0000 a 0099 authorizes the transaction
        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response < 100) {
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }

        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response > 100) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error removing payment UUID {0} calling borraPreferencia with error code: {1}', paymentUUID, decodedResponse.Ds_Response);
        }

        // Remove payment instrument from wallet if not exist in Redsys
        if (decodedResponse.message === 'SIS0467') {
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }
    }

    if (srvResponse.errorMessage) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling borraPreferencia: {0}', decodedResponse.message);
    }

    return { status: status, response: decodedResponse };
}

/**
 * Request to get credit card version to use the proper protocol
 * @param {dw.order.Order} order - Customers's order
 * @return {Object/boolean} returns an error object / false
 */
function iniciaPeticionRefund(order, amount) {
    //var amount = redsysHelper.calculateAmount(order.paymentTransaction.amount.value);
    var status = redsysConstants.REDSYS_RESPONSE_FAIL;
    var srvResponse = null;
    var decodedResponse = null;
    var iniciaPeticionResponse = null;

    if (!order) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Order not exist');
    }
    var config = redsysHelper.getRedsysIniciaPeticionRefundConfig(order.orderNo, amount);
    if (config.error) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
    }

    var params = redsysHelper.makeParameters(
        redsysConstants.REDSYS_SERVICE_INICIA_PETICION_REST,
        order.paymentInstrument.paymentMethod,
        config,
        order.orderNo
    );

    try {
        srvResponse = redsysService.createHttpService.call(params);
    } catch (e) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling Redsys service: {0}}', e.message);
    }

    if (srvResponse.isOk()) {
        decodedResponse = redsysHelper.decodeResponse(srvResponse);
        if (decodedResponse.error) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error calling iniciaPeticion: {0}', decodedResponse.message);
        } else {
            iniciaPeticionResponse = decodedResponse;
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }
    }

    if (srvResponse.errorMessage) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling iniciaPeticion: {0}', decodedResponse.message);
    }

    return { status: status, response: iniciaPeticionResponse };
}

/**
 * Request to get credit card version to use the proper protocol
 * @param {dbject} iniciaPeticionResponse - Customers's order
 * @param {dw.order.Order} order - Customers's order
 * @return {Object} returns an error object
 */
function trataPeticionRefund(order, amount) {
    var amount = redsysHelper.calculateAmount(amount);
    var status = redsysConstants.REDSYS_RESPONSE_FAIL;
    var message = "";
    var typeOfResponse = redsysConstants.REDSYS_FRICTIONLESS;
    var threeDSMethodURL = null;
    var srvResponse = null;
    var decodedResponse = null;
    var trataPeticionResponse = null;
    var signature = null;

    var config = redsysHelper.getRedsysIniciaPeticionRefundConfig(order, amount);
    if (config.error) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
    }

    var params = redsysHelper.makeParameters(
        redsysConstants.REDSYS_SERVICE_TRATA_PETICION_REST,
        order.paymentInstrument.paymentMethod,
        config,
        order.orderNo
    );

    try {
        srvResponse = redsysService.createHttpService.call(params);
    } catch (e) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error calling Redsys service: {0}}', e.message);
    }

    if (srvResponse.isOk()) {
        decodedResponse = redsysHelper.decodeResponse(srvResponse);
        signature = JSON.parse(srvResponse.object).Ds_Signature;
        if (decodedResponse.error) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            message = decodedResponse.message;
            logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, decodedResponse.message);
        }

        // Ds_Response codes from 0000 a 0099 authorizes the transaction
        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response == 900) {
            trataPeticionResponse = decodedResponse;
            status = redsysConstants.REDSYS_RESPONSE_PASS;
        }

        if (decodedResponse.Ds_Response && decodedResponse.Ds_Response != 900) {
            status = redsysConstants.REDSYS_RESPONSE_FAIL;
            logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, decodedResponse.Ds_Response);
        }

        if (decodedResponse.Ds_EMV3DS && decodedResponse.Ds_EMV3DS.threeDSInfo === redsysConstants.REDSYS_EMV3DS_CHALLENGE_REQUEST) {
            trataPeticionResponse = decodedResponse;
            status = redsysConstants.REDSYS_RESPONSE_PASS;
            typeOfResponse = redsysConstants.REDSYS_EMV3DS_CHALLENGE_REQUEST;
            threeDSMethodURL = iniciaPeticionResponse.Ds_EMV3DS.threeDSMethodURL ? 'Y' : 'N';
        }
    }

    if (srvResponse.errorMessage) {
        status = redsysConstants.REDSYS_RESPONSE_FAIL;
        logger.error('Error in order {0} calling trataPeticion: {1}', order.orderNo, decodedResponse.message);
    }

    return { status: status, typeOfResponse: typeOfResponse, threeDSMethodURL: threeDSMethodURL, response: trataPeticionResponse, signature: signature, message: message };
}

module.exports = {
    iniciaPeticion: iniciaPeticion,
    trataPeticion: trataPeticion,
    autenticacion: autenticacion,
    borraPreferencia: borraPreferencia,
    iniciaPeticionRefund: iniciaPeticionRefund,
    trataPeticionRefund: trataPeticionRefund
};
