const path = require('path');
const configParser = require('../../config');
const depTypeWorker = require('../dep-type');
const configValidation = require('../../config/validation');

let logger = require('../../logger');

module.exports = {
  renovatePackageFile,
  getDepTypeConfig,
};

async function renovatePackageFile(packageFileConfig) {
  let config = Object.assign({}, packageFileConfig);
  let upgrades = [];
  logger = config.logger;
  logger.info(`Processing package file`);
  // If onboarding, use the package.json in onboarding branch unless a custom base branch was defined
  const packageContent = await config.api.getFileJson(
    config.packageFile,
    config.contentBaseBranch
  );

  if (!packageContent) {
    config.depName = config.packageFile;
    config.type = 'error';
    config.message = 'No json content found';
    logger.warn(config.message);
    return [config];
  }

  // Check for renovate config inside the package.json
  if (packageContent.renovate) {
    logger.trace(
      { config: packageContent.renovate },
      'package.json>renovate config'
    );
    const errors = configValidation.validateConfig(packageContent.renovate);
    if (errors.length) {
      logger.warn(
        { errors },
        'Found package.json>renovate configuration errors'
      );
      /* TODO #556
      errors.forEach(error => {
        upgrades.push(
          Object.assign({}, error, {
            depName: `${config.packageFile}(renovate)`,
            type: 'error',
          })
        );
      });
      */
    }
    // package.json>renovate config takes precedence over existing config
    config = configParser.mergeChildConfig(config, packageContent.renovate);
  } else {
    logger.debug('Package file has no renovate configuration');
  }
  // Now check if config is disabled
  if (config.enabled === false) {
    logger.info('packageFile is disabled');
    return upgrades;
  }

  const depTypeConfigs = config.depTypes.map(depType =>
    module.exports.getDepTypeConfig(config, depType)
  );
  logger.trace({ config: depTypeConfigs }, `depTypeConfigs`);
  for (const depTypeConfig of depTypeConfigs) {
    upgrades = upgrades.concat(
      await depTypeWorker.renovateDepType(packageContent, depTypeConfig)
    );
  }

  // Detect if a yarn.lock file is in use
  const yarnLockFileName = path.join(
    path.dirname(config.packageFile),
    'yarn.lock'
  );
  if (await config.api.getFileContent(yarnLockFileName)) {
    config.hasYarnLock = true;
  }
  const packageLockFileName = path.join(
    path.dirname(config.packageFile),
    'package-lock.json'
  );
  if (await config.api.getFileContent(packageLockFileName)) {
    config.hasPackageLock = true;
  }
  if (
    config.lockFileMaintenance.enabled &&
    (config.hasYarnLock || config.hasPackageLock)
  ) {
    logger.debug('lockFileMaintenance enabled');
    // Maintain lock files
    const lockFileMaintenanceConf = configParser.mergeChildConfig(
      config,
      config.lockFileMaintenance
    );
    lockFileMaintenanceConf.type = 'lockFileMaintenance';
    logger.debug(
      { config: lockFileMaintenanceConf },
      `lockFileMaintenanceConf`
    );
    upgrades.push(lockFileMaintenanceConf);
  }

  logger.info('Finished processing package file');
  return upgrades;
}

function getDepTypeConfig(packageFileConfig, depType) {
  let depTypeConfig = typeof depType === 'string' ? { depType } : depType;
  depTypeConfig = configParser.mergeChildConfig(
    packageFileConfig,
    depTypeConfig
  );
  depTypeConfig.logger = logger.child({
    repository: depTypeConfig.repository,
    packageFile: depTypeConfig.packageFile,
    depType: depTypeConfig.depType,
  });
  return configParser.filterConfig(depTypeConfig, 'depType');
}