const R = require('ramda');
const { EventEmitter } = require('events');
const logger = require('../logger');
const getProxySettings = require('../getProxySettings');
const applyLoggingOptions = require('./applyLoggingOptions');
const validateConfig = require('./validateConfig');
const { normalizeConfig } = require('./normalizeConfig');

const defaultConfig = {
  http: {},
  server: null,
  // emitter: new EventEmitter(), // TODO Merge + preserve prototype?
  custom: {
    cwd: process.cwd(),
  },
  path: [],
  apiDescriptions: [],
  'dry-run': false,
  reporter: null,
  output: null,
  header: null,
  user: null,
  'inline-errors': false,
  details: false,
  method: [],
  only: [],
  color: true,
  loglevel: 'warn',
  sorted: false,
  names: false,
  hookfiles: [],
  language: 'nodejs',
  'hooks-worker-timeout': 5000,
  'hooks-worker-connect-timeout': 1500,
  'hooks-worker-connect-retry': 500,
  'hooks-worker-after-connect-wait': 100,
  'hooks-worker-term-timeout': 5000,
  'hooks-worker-term-retry': 500,
  'hooks-worker-handler-host': '127.0.0.1',
  'hooks-worker-handler-port': 61321,
};

/**
 * Flattens giving configuration Object, removing nested "options" key.
 * This makes it possible to use nested "options" key without introducing
 * a breaking change to the library's public API.
 * TODO Remove this method after "options" key is removed in the next
 * major version. Document the removal of "options" in the Dredd docs.
 */
function flattenConfig(config) {
  const nestedOptions = R.prop('options', config);
  const rootOptions = R.omit(['options'], config);

  if (nestedOptions) {
    logger.warn('Deprecated usage of `options` in Dredd configuration.');
  }

  return R.mergeDeepLeft(nestedOptions || {}, rootOptions);
}

function resolveConfig(config) {
  const inConfig = R.compose(
    // Set "emitter" property explicitly to preserve its prototype.
    // During deep merge Ramda omits prototypes, breaking emitter.
    R.assoc('emitter', R.propOr(new EventEmitter(), 'emitter', config)),
    R.mergeDeepRight(defaultConfig),
    flattenConfig
  )(config);

  // Validate Dredd configuration
  const { warnings, errors } = validateConfig(inConfig);
  warnings.forEach(message => logger.warn(message));
  errors.forEach(message => logger.error(message));

  // Fail fast upon any Dredd configuration errors
  if (errors.length > 0) {
    throw new Error('Could not configure Dredd');
  }

  return {
    config: normalizeConfig(inConfig),
    warnings,
    errors,
  };
}

function applyConfiguration(config) {
  const { config: resolvedConfig } = resolveConfig(config);

  applyLoggingOptions(resolvedConfig);

  // Log information about the HTTP proxy settings
  const proxySettings = getProxySettings(process.env);
  if (proxySettings.length) {
    logger.warn(
      `HTTP(S) proxy specified by environment variables: ${proxySettings.join(', ')}. `
      + 'Please read documentation on how Dredd works with proxies: '
      + 'https://dredd.org/en/latest/how-it-works/#using-https-proxy'
    );
  }

  return resolvedConfig;
}

module.exports = {
  applyConfiguration,
  resolveConfig,
  _utils: {
    defaultConfig,
  },
};

@@ -61,24 +61,25 @@
 ('events');%0A
+%0A
 const logger
@@ -339,29 +339,30 @@
 %0A%0Aconst 
-defaultConfig
+DEFAULT_CONFIG
  = %7B%0A  h
@@ -395,72 +395,340 @@
  // 
-emitter: new EventEmitter(), // TODO Merge + preserve prototype?
+TODO Find a way to deep merge default and custom configs%0A  // while presering prototypes.%0A  // When the next line is uncommented, %22emitter%22 property will be processed%0A  // during %22R.mergeDeepX%22 call, resulting into EventEmitter's instance prototype%0A  // not being copied. This breaks event emitter.%0A  // emitter: new EventEmitter(),
 %0A  c
@@ -1388,19 +1388,18 @@
 tens giv
-ing
+en
  configu
@@ -2306,29 +2306,30 @@
 epRight(
-defaultConfig
+DEFAULT_CONFIG
 ),%0A    f
@@ -3407,21 +3407,22 @@
     
-defaultConfig
+DEFAULT_CONFIG
 ,%0A  

add explanatory comment upon configuration emitter