import {cosmiconfig, PublicExplorer} from 'cosmiconfig';
import {SCConfigFile} from '@openstapps/core';
import path from 'path';
import deepmerge from 'deepmerge';

const fallbackNamespace = 'default';
const configPath = 'config';

/**
 * Creates a config loader
 * @param moduleName the name of the config file (module)
 */
function configLoader(moduleName: string): PublicExplorer {
  return cosmiconfig(moduleName, {
    searchPlaces: ['js', 'json', 'yml', 'yaml'].map(it => `${moduleName}rc.${it}`),
    loaders: {
      '.js': filepath => import(`file://${filepath}`).then(it => it.default),
    },
  });
}

/**
 * Find and load a config file
 */
async function findConfig<T>(moduleName: string, namespace = fallbackNamespace): Promise<T> {
  return configLoader(moduleName)
    .search(path.posix.join('.', configPath, namespace))
    .then(it => it!.config as T)
    .catch(() =>
      configLoader(moduleName)
        .search(path.posix.join('.', configPath, fallbackNamespace))
        .then(it => it!.config),
    );
}

/**
 * Loads a config file
 */
async function loadConfig<T>(moduleName: string): Promise<T> {
  const namespace = process.env.NODE_APP_INSTANCE;
  const database = process.env.NODE_CONFIG_ENV;

  const config = await findConfig<T>(moduleName, namespace);
  if (database) {
    const databaseConfig = await findConfig<T>(database, namespace);
    return deepmerge(config, databaseConfig);
  }

  return config;
}

export const backendConfig = await loadConfig<SCConfigFile>('backend');
export const prometheusConfig = await loadConfig<unknown>('prometheus');
