'use strict';

var utilHttp = require('../utils/UtilHttp');
var utilHttpStatus =  require('../../shared/utils/UtilHttpStatus');
var sharedConstants = require('../../shared/constants/SharedConstants');
var utilCustomComponent = require('../../server/utils/UtilCustomComponent');
var UtilValidation = require('../../shared/utils/UtilValidation');
var NodeVM = require('vm2').NodeVM;
var q = require("q");
var UtilError = require('../../shared/utils/UtilError');
var SearchResultsProcessor = require('../../shared/utils/SearchResultsProcessor');
var SearchService = require('../search/SearchService');
// {
//   functionName: getAddress,
//   functionParameters: [”Smith St”, “Geelong”]
//   componentDocumentName: <documentId or name of component>
// }

/**
 * Used to execute component restfulWebServiceFunction with a provided user, componentName , functionName
 * and additionaly functionParameters which is optional
 * @param req (included provided user, componentName, functionName and functionParameters)
 * @param res (return result: error, objects)
 */
exports.executeFunction = function(req, res) {
	var userId = req.user.documentId;
	var funcName = req.params.functionName || req.body.functionName;
	var componentName = req.params.componentName 
        || req.body.componentWebServiceName || req.body.componentDocumentName;
	var funcParams = req.body.functionParameters;

	//process the request
	var customComponent = {
		componentName: componentName
	};

	if (!componentName){
        var errMsg = "Component name must be provided";
        res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(errMsg);
	}
	else if (!funcName){
        var errMsg = "Component function name must be provided";
        res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(errMsg);
	}
	else {

	    let options = {
	        targetOperation: sharedConstants.OPERATION_TYPE_EXECUTE,
            targetFieldNames: ["restfulWebServiceFunctions"]
        };

        utilCustomComponent.getComponent(customComponent, userId, options)
            .then(function successFunc(result) {
                try {
                    var func = result.restfulWebServiceFunctions;
                    if (UtilValidation.hasValue(func)) {

                        const { getBuiltInWhitelist, getExternalWhitelist, getRoot } =
                            require("./../utils/UtilSandbox");

                        var vm = new NodeVM({
                            sandbox: {
                                userId: userId,
                                logger: logger,
                                config: config,
                                SharedConstants: sharedConstants,
                                DataService: DataService,
                                SearchService: SearchService,
                                SearchResultsProcessor: SearchResultsProcessor,
                                q: q,
                                req: req
                            },
                            require: {
                                external: getExternalWhitelist(),
                                builtin: getBuiltInWhitelist(),
                                root: getRoot()
                            }
                        });

                        // run the ruleset script via sandbox.
                        // Global, built-in and external libraries
                        // wont be available not unless specified in the above NodeVM
                        var execFunc = vm.run("module.exports = \n " + func + ";", getRoot() + '/vm.js');

                        execFunc[funcName](funcParams, req).then(function successFunc(data) {
                            let status = data.statusCode || 200;
                            res.status(status).json(data);
                        }, function errorFunc(err) {
                            res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(err);
                        });

                    } else {
                        var errMsg = "Invalid custom component function";
                        res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(errMsg);
                    }
                } catch (err) {
                    var errMsg = ("Error in running custom component function " + funcName + " : " + err.message);
                    logger.error(errMsg);
                    res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(errMsg);
                }

            }, function errorFunc(err) {
                if (err.name === UtilError.FORBIDDEN_ERROR) {
                    res.status(utilHttpStatus.FORBIDDEN).send(err.message);
                } else {
                    res.status(utilHttpStatus.INTERNAL_SERVER_ERROR).send(err.message);
                }
            });
    }
};
