const handlebars = require('handlebars');
const slugify = require('slugify');
const cleanGitRef = require('clean-git-ref').clean;

const { generateBranchConfig } = require('./generate');
const { flattenUpdates } = require('./flatten');

/**
 * Clean git branch name
 *
 * Remove what clean-git-ref fails to:
 * - leading dot/leading dot after slash
 * - trailing dot
 * - whitespace
 */
function cleanBranchName(branchName) {
  return cleanGitRef(branchName)
    .replace(/^\.|\.$/, '') // leading or trailing dot
    .replace(/\/\./g, '/') // leading dot after slash
    .replace(/\s/g, ''); // whitespace
}

function branchifyUpgrades(config, packageFiles) {
  logger.debug('branchifyUpgrades');
  const updates = flattenUpdates(config, packageFiles);
  logger.debug(`${updates.length} updates found`);
  logger.debug({ upgradeNames: updates.map(u => u.depName) });
  const errors = [];
  const warnings = [];
  const branchUpgrades = {};
  const branches = [];
  for (const u of updates) {
    const update = { ...u };
    // Split out errors and warnings first
    if (update.updateType === 'error') {
      errors.push(update);
    } else if (update.updateType === 'warning') {
      warnings.push(update);
    } else {
      // Massage legacy vars just in case
      update.currentVersion = update.currentValue;
      update.newVersion = update.newValue;
      // massage for handlebars
      const upper = str => str.charAt(0).toUpperCase() + str.substr(1);
      if (update.updateType) {
        update[`is${upper(update.updateType)}`] = true;
      }
      // Check whether to use a group name
      if (update.groupName) {
        logger.debug('Using group branchName template');
        logger.debug(
          `Dependency ${update.depName} is part of group ${update.groupName}`
        );
        update.groupSlug = slugify(update.groupSlug || update.groupName, {
          lower: true,
        });
        update.branchTopic = update.group.branchTopic || update.branchTopic;
        update.branchName = handlebars.compile(
          update.group.branchName || update.branchName
        )(update);
      } else {
        update.branchName = handlebars.compile(update.branchName)(update);
      }
      // Compile extra times in case of nested handlebars templates
      update.branchName = handlebars.compile(update.branchName)(update);
      update.branchName = cleanBranchName(
        handlebars.compile(update.branchName)(update)
      );

      branchUpgrades[update.branchName] =
        branchUpgrades[update.branchName] || [];
      branchUpgrades[update.branchName] = [update].concat(
        branchUpgrades[update.branchName]
      );
    }
  }
  logger.debug(`Returning ${Object.keys(branchUpgrades).length} branch(es)`);
  for (const branchName of Object.keys(branchUpgrades)) {
    logger.setMeta({
      repository: config.repository,
      branch: branchName,
    });
    const branch = generateBranchConfig(branchUpgrades[branchName]);
    branch.branchName = branchName;
    branches.push(branch);
  }
  logger.setMeta({
    repository: config.repository,
  });
  logger.debug(`config.repoIsOnboarded=${config.repoIsOnboarded}`);
  const branchList = config.repoIsOnboarded
    ? branches.map(upgrade => upgrade.branchName)
    : config.branchList;
  return {
    errors: config.errors.concat(errors),
    warnings: config.warnings.concat(warnings),
    branches,
    branchList,
  };
}

module.exports = {
  branchifyUpgrades,
};