const timerName = "Startup time";
console.time(timerName);
console.log("Starting.");

process.env.isDevBuild = true;
process.traceDeprecation = true;
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; // Disables certificate validation.
process.env["ISC_WINSTON_CLI_FORMAT"] = 1;

const fs = require("fs");
const path = require("path");

if (!fs.existsSync("./config/settings.js")) {
    fs.copyFileSync(path.resolve(__dirname, "./config/settings-base.js"), "./config/settings.js");
}

const settings = require("./config/settings");

if (!process.env.ISC_API_URL) {
    process.env.ISC_API_URL = settings.apiUrl;
}

if (!process.env.ISC_API_URL.startsWith("http")) {
    console.warn("ISC_API_URL doesn't start with `http`, prefixing with `http://`.");
    process.env.ISC_API_URL = `http://${process.env.ISC_API_URL}`;
} else if (process.env.ISC_API_URL.startsWith("https")) {
    // When HTTPS is used to connect to ISC, cookies may get the Secure attribute.
    // The browser will drop cookies with the Secure attribute when received over an unencrypted (http) connection.
    // We're not using encryption with Node (at the time of writing), so this warning should be taken seriously.
    console.warn("ISC_API_URL starts with `https`, which may cause authorization cookies to be dropped.");
}

if (!process.env.BUILD_INFO) {
    process.env.BUILD_INFO = "Development";
}

const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const webpackConfig = require("./config/webpack/dev");

const compiler = webpack(webpackConfig);

const stats = {
    builtAt: false,
    colors: true,
    hash: false,
    modules: false,
    performance: false,
    entrypoints: false,
    timings: false,
    version: false,
    warningsFilter: [/Critical dependency: the request of a dependency is an expression/],
};

const clientCompiler = compiler.compilers.find(compiler => compiler.name === "client");
const clientWebpackDevMiddleware = webpackDevMiddleware(clientCompiler, {
    publicPath: clientCompiler.options.output.publicPath,
    stats,
});

const clientShellCompiler = compiler.compilers.find(compiler => compiler.name === "client-shell");
const clientShellWebpackDevMiddleware = webpackDevMiddleware(clientShellCompiler, {
    publicPath: clientShellCompiler.options.output.publicPath,
    stats,
});

const serverCompiler = compiler.compilers.find(compiler => compiler.name === "server");
const serverWebpackDevMiddleware = webpackDevMiddleware(serverCompiler, {
    stats,
    serverSideRender: true,
});

let serverHash = "";
let server = null;

const Module = require("module");

let serverOutputPath;

const [, , portArg, orPortArg] = process.argv;
// eslint-disable-next-line no-restricted-globals
const thePort = portArg && !isNaN(portArg) ? portArg : orPortArg && !isNaN(orPortArg) ? orPortArg : 3000;

const getOptions = port => {
    return {
        setupExtraMiddleware: app => {
            app.use(clientWebpackDevMiddleware);
            app.use(clientShellWebpackDevMiddleware);
            app.use(serverWebpackDevMiddleware);
            app.use(webpackHotMiddleware(clientCompiler));
            app.use(webpackHotMiddleware(clientShellCompiler));
            app.use(webpackHotMiddleware(serverCompiler));
        },
        getServer: response => {
            const { devMiddleware } = response.locals.webpack;
            if (serverHash !== devMiddleware.stats.hash) {
                if (!serverOutputPath) {
                    serverOutputPath = devMiddleware.stats.toJson().outputPath;
                }

                const memoryServer = new Module();

                memoryServer._compile(
                    devMiddleware.outputFileSystem.readFileSync(`${serverOutputPath}/server.js`, "utf8"),
                    "",
                );
                server = memoryServer.exports.server;
                serverHash = devMiddleware.stats.hash;
            }
            return server;
        },
        finishSetup: app => {
            clientWebpackDevMiddleware.waitUntilValid(() =>
                clientShellWebpackDevMiddleware.waitUntilValid(() =>
                    serverWebpackDevMiddleware.waitUntilValid(() => {
                        app.listen(port, () => {
                            console.log(`Startup complete, listening on port ${port}.`);
                            console.timeEnd(timerName);
                        });
                    }),
                ),
            );
        },
    };
};

const start = require("./start");

start(getOptions(thePort));

// this handles starting a second listener for netcore
// and works with some code in ServerSideRendering to handle sending API requests to the proper location
if (fs.existsSync("../../.env")) {
    let ingressPort = 0;
    let nodePort = 0;
    fs.readFile("../../.env", "utf8", (err, data) => {
        const lines = data.split(/\r?\n|\r|\n/g);
        for (let x = 0; x < lines.length; x++) {
            if (lines[x].startsWith("SPIRE_WEB_PORT=")) {
                nodePort = parseInt(lines[x].replace("SPIRE_WEB_PORT=", ""), 10);
            } else if (lines[x].startsWith("SPIRE_PORT=")) {
                ingressPort = parseInt(lines[x].replace("SPIRE_PORT=", ""), 10);
            }
        }

        if (nodePort !== 0 && ingressPort !== 0) {
            process.env.SECONDARY_INGRESS_PORT = ingressPort;
            start(getOptions(nodePort));
        }
    });
}
