let loopback = require('loopback');
let boot = require('loopback-boot');
let DataSource = require('loopback-datasource-juggler').DataSource;
let fs = require('fs-extra');
let i18n = require('i18n');
let path = require('path');
const loopbackConnector = require('loopback-connector');

let _resolveConnector = DataSource._resolveConnector;

DataSource._resolveConnector = function(name) {
    let testPath = `${__dirname}/connectors/${name}.js`;

    if (fs.existsSync(testPath))
        return {
            connector: require(testPath),
            error: null
        };

    return _resolveConnector.apply(this, arguments);
};

module.exports = {
    loopback: loopback,
    loopbackConnector: loopbackConnector,
    boot: vnBoot
};

function vnBoot(app, rootDir, rootModule) {
    // Internationalization

    let localeDir = `${__dirname}/../common/locale`;

    if (fs.existsSync(localeDir)) {
        i18n.configure({
            directory: localeDir,
            defaultLocale: 'es'
        });

        app.use(i18n.init);
    }

    // View

    let wpAssets;
    let viewDir = `${rootDir}/../client`;

    if (fs.existsSync(viewDir)) {
        try {
            wpAssets = require('../client/webpack-assets.json');
        } catch (e) {}

        app.set('view engine', 'ejs');
        app.set('views', viewDir);
        app.use(loopback.static(path.resolve(rootDir, '../client')));
    }

    const buildVersion = new Date().getTime();

    app.renderIndex = async res => {
        res.render(`${viewDir}/index.ejs`, {
            assets: assets,
            version: buildVersion
        });

        function assets(main, deps) {
            let jsFiles;

            if (wpAssets) {
                jsFiles = [wpAssets.manifest.js];

                for (let dep of deps)
                    jsFiles.push(wpAssets[dep].js);

                jsFiles.push(wpAssets[main].js);
            } else {
                let publicPath = '/static';
                jsFiles = [`${publicPath}/manifest.js`];

                for (let dep of deps)
                    jsFiles.push(`${publicPath}/${dep}.js`);

                jsFiles.push(`${publicPath}/${main}.js`);
            }

            return jsFiles;
        }
    };

    // Initialization

    app.start = port => {
        function onListen() {
            app.emit('started');
            let packageJson = require(`${rootDir}/../package.json`);
            let appName = packageJson.name;
            let baseUrl = app.get('url').replace(/\/$/, '');
            console.log(`Web server ${appName} listening at: %s`, `${baseUrl}/explorer`);
        }

        let args = port ? [port, onListen] : [onListen];
        return app.listen.apply(app, args);
    };

    let config = require('./config.json');

    for (let key in config) {
        app.set(key, config[key]);
    }

    let modelConfigFiles = [
        `${__dirname}/model-config.json`,
        `${rootDir}/model-config.json`
    ];

    let modelConfig = {};

    for (file of modelConfigFiles)
        if (fs.existsSync(file))
            Object.assign(modelConfig, require(file));

    let bootOptions = {
        appRootDir: __dirname,
        appConfigRootDir: rootDir,
        modelsRootDir: rootDir,
        models: modelConfig,
        modelSources: [
            `loopback/common/models`,
            `loopback/server/models`,
            `${__dirname}/../common/models`,
            `${rootDir}/../common/models`
        ],
        mixinDirs: [
            `loopback/common/mixins`,
            `loopback/server/mixins`,
            `${__dirname}/../common/mixins`,
            `${rootDir}/../common/mixins`
        ],
        bootDirs: [
            `${__dirname}/boot`,
            `${rootDir}/boot`
        ]
    };

    boot(app, bootOptions, function(err) {
        if (err) throw err;
        if (require.main === rootModule)
            app.start();
    });
}