'use strict';

var MongoClient = require('mongodb').MongoClient;
var ServerConstants = require('../../../constants/ServerConstants');
var utilConfig = require('../../../utils/UtilConfig');
var logger = require('../../../utils/Logger').loggers.get('db');
var dbConfig = require('../DatabaseConfig');

module.exports.getConfig = async function(conf) {

    logger.info("Connecting to Mongodb database to load configuration");

    const mongo = dbConfig.getDataServicesConfig();
    const connectionURL = require('./MongoURL')();

    // fetch client
    let client;
    try{
        client = await MongoClient.connect(connectionURL, {
          ...(mongo.mongoConnectionOptions),
          useNewUrlParser: true
        });
    }catch (err) {
        throw displayAndRecreateError(SharedConstants.ERROR_DB_CONNECTION + ":" + err);
    }

    const isValid = await isValidDB(client);
    if (!isValid){
      throw displayAndRecreateError(SharedConstants.ERROR_DB_CONNECTION +
        ": invalid database " + client.db().databaseName );
    }

    // fetch collection
    let collection;
    try{
        const mongo = dbConfig.getDataServicesConfig();
        let collectionName = mongo.collection ? mongo.collection : ServerConstants.MONGO_COLLECTION_NAME;
        collection = client.db().collection(collectionName);

    }catch (err) {
        throw displayAndRecreateError("Error creating collection to load configuration: " + err);
    }

    // there can only be one document with a systemHeader.systemType of configuration,
    // otherwise we'd have problems
    // with the wrong config being loaded. It's better to load by systemHeader.systemType
    // so that we don't have to
    // put a configuration value in for the config document id.
    // We can enforce the rule of one configuration document
    // only through
    const configQuery = {
        "systemHeader.systemType": SharedConstants.SYSTEM_TYPE_CONFIGURATION,
        "systemHeader.currentVersion": true
    };

    try{
        const doc = await collection.findOne(configQuery);
        if (doc) {
            logger.info("Successfully loaded configuration document from database");
            utilConfig.mergeConfigs(conf, doc);
        }else{
            const msg = "Config not found in the database, using the configuration " +
                "from file with no database overrides";
            logger.warn(msg);
        }
    }catch(err){
        throw displayAndRecreateError("Error finding config document in database: " + err);
    }

    return conf;

    // END -- Helpers below

    function displayAndRecreateError(message, origError){
        logger.error(message);
        logger.error(origError);
        return new Error(message);
    }

    async function isValidDB(client){
      const db = client.db();
      const dbName =db.databaseName;
      const databasesList = await db.admin().listDatabases();
      const retVal = databasesList.databases.some(db => db.name === dbName);
      return retVal;
    }
};
