/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var when = require("when");
var http = require('http');
var express = require("express");
var fs = require('fs-extra');
var path = require('path');
var app = express();

var RED = require("nr-test-utils").require("node-red/lib/red.js");

var utilPage = require("./pageobjects/util/util_page");

var server;
var homeDir = './test/resources/home';
var address = '127.0.0.1';
var listenPort = 0; // use ephemeral port
var url;
/*
 * Set false when you need a flow to reproduce the failed test case.
 * The flow file is under "homeDir" defined above.
 */
var isDeleteFlow = true;

function getFlowFilename() {
    var orig = Error.prepareStackTrace;
    var err = new Error();
    Error.prepareStackTrace = function (err, stack) {
        return stack;
    };
    // Two level higher caller is the actual caller (e.g. a caller of startServer).
    var filepath = err.stack[2].getFileName();
    var filename = path.basename(filepath, ".js");
    Error.prepareStackTrace = orig;

    var flowFile = 'flows_' + filename + '.json';
    return flowFile;
}

function cleanup(flowFile) {
    var credentialFile = flowFile.replace(/\.json$/, '') + '_cred.json';
    deleteFile(homeDir + "/" + flowFile);
    deleteFile(homeDir + "/." + flowFile + ".backup");
    deleteFile(homeDir + "/" + credentialFile);
    deleteFile(homeDir + "/." + credentialFile + ".backup");
    deleteFile(homeDir + "/package.json");
    deleteFile(homeDir + "/lib/flows");
    deleteFile(homeDir + "/lib");
}

function deleteFile(flowFile) {
    try {
        fs.statSync(flowFile);
        if (isDeleteFlow) {
            fs.unlinkSync(flowFile);
        }
    } catch (e) {}
}

module.exports = {
    startServer: function() {
        try{
            utilPage.init();

            // Name a flow file including caller filename so that multiple Node-RED servers can run simultaneously.
            // Call this method here because retrieving the caller filename by call stack.
            var flowFilename = getFlowFilename();
            browser.windowHandleMaximize();
            browser.call(function () {
                return new Promise(function(resolve, reject) {
                    cleanup(flowFilename);
                    server = http.createServer(app);
                    var settings = {
                        httpAdminRoot: "/",
                        httpNodeRoot: "/api",
                        userDir: homeDir,
                        flowFile: flowFilename,
                        functionGlobalContext: { },    // enables global context
                        SKIP_BUILD_CHECK: true,
                        logging: {console: {level:'off'}}
                    };
                    RED.init(server, settings);
                    app.use(settings.httpAdminRoot,RED.httpAdmin);
                    app.use(settings.httpNodeRoot,RED.httpNode);
                    server.listen(listenPort, address);
                    server.on('listening', function() {
                        var port = server.address().port;
                        url = 'http://' + address + ':' + port;
                    });
                    RED.start().then(function() {
                        resolve();
                    });
                });
            });
            browser.url(url);
            browser.waitForExist(".red-ui-palette-node[data-palette-type='inject']");
        } catch (err) {
            console.log(err);
            throw err;
        }
    },

    stopServer: function(done) {
        try {
            // Call this method here because retrieving the caller filename by call stack.
            var flowFilename = getFlowFilename();
            browser.call(function () {
                browser.close();  // need to call this inside browser.call().
                return when.promise(function(resolve, reject) {
                    if (server) {
                        RED.stop().then(function() {
                            server.close(function() {
                                cleanup(flowFilename);
                                resolve();
                            });
                        });
                    } else {
                        cleanup(flowFilename);
                        resolve();
                    }
                });
            });
        } catch (err) {
            console.log(err);
            throw err;
        }
    },

    url: function() {
        return url;
    },

    red: function() {
        return RED;
    },
};