const fs = require('fs');
const chalk = require('chalk');

function mapPacks(target, collection, versionFn, source) {
  Object.keys(collection).forEach(key => {
    const item = {
      name: key,
      version: versionFn(collection[key]),
    };
    
    if (source) { item.source = source; }

    if (!target[key]) {
      target[key] = item;
    } else {
      target[key].duplicates = (target[key].duplicates || []).push(item);
    }
  });
}
function mapPackages(target, collection, source) {
  mapPacks(target, collection, v => v, source);
}
function mapLockPackages(target, collection) {
  mapPacks(target, collection, v => v.version);
}

function checkAndUpdatePackagesVersions(pkg, lockPkg, options) {
  const packagesMap = {};
  mapPackages(packagesMap, pkg.dependencies, 'dependencies');
  mapPackages(packagesMap, pkg.devDependencies, 'devDependencies');

  const lockPackagesMap = {};
  mapLockPackages(lockPackagesMap, lockPkg.dependencies);

  const packages = Object.keys(packagesMap).map(k => packagesMap[k]);
  const diffs = [];
  const missing = [];

  packages.forEach(p => {
    const lockP = lockPackagesMap[p.name];
    const item = {
      name: p.name,
      version: p.version,
      source: p.source
    };

    if (!lockP) {
      missing.push(item)
      return;
    }
    // strip non-digits and see what's left
    const diff = p.version.replace(lockP.version, '').replace(/\D/ig, '').length;
    if (diff) {
      item.lockVersion = lockP.version;
      diffs.push(item);
    }
  });

  console.log(`Running in ${chalk.default.magentaBright(options.fix ? 'FIX' : 'CHECK')} mode\n`);

  diffs.forEach(p => {
    console.log(`${chalk.default.greenBright(p.name)} ${chalk.default.yellow(p.version)} =/= ${chalk.default.yellowBright(p.lockVersion)}`);
    if (options.fix) {
      pkg[p.source][p.name] = p.lockVersion;
    }
  });

  let resultMessage = `Checked packages: ${chalk.default.greenBright(packages.length.toFixed(0))}.\nFound differences: ${chalk.default.redBright(diffs.length.toFixed(0))}`;
  return (!options.fix
    ? Promise.resolve(resultMessage)
    : new Promise(resolve => {
        fs.writeFile('./package.json', JSON.stringify(pkg, null, '  '), 'utf8', (err) => {
          resolve(err ? err : resultMessage + `\nFixed packages: ${chalk.default.greenBright(diffs.length.toFixed(0))}`);
        });
      })
    ).then(msg => {
      console.log(`\n${msg}\n`);
      
      if(missing.length){
        console.log('Missing lock entires:');
        missing.forEach(p => console.log(`${p.name} ${p.version}`));
      }
    });
}

module.exports = checkAndUpdatePackagesVersions;