import fs from 'fs';
import path from 'path';
import yargs from 'yargs';
import lodash from 'lodash';
import depcheck from './index';
import { version } from '../package.json';

function checkPathExist(dir) {
  return new Promise((resolve, reject) =>
    fs.exists(dir, result => result ? resolve() : reject()));
}

function getParsers(parsers) {
  return lodash.isUndefined(parsers)
    ? undefined
    : lodash(parsers)
      .split(',')
      .map(keyValuePair => keyValuePair.split(':'))
      .fromPairs()
      .mapValues(value => value.split('&').map(name => depcheck.parser[name]))
      .value();
}

function getDetectors(detectors) {
  return lodash.isUndefined(detectors)
    ? undefined
    : detectors.split(',').map(name => depcheck.detector[name]);
}

function getSpecials(specials) {
  return lodash.isUndefined(specials)
    ? undefined
    : specials.split(',').map(name => depcheck.special[name]);
}

function noIssue(result) {
  return lodash.isEmpty(result.dependencies)
      && lodash.isEmpty(result.devDependencies)
      && lodash.isEmpty(result.missing);
}

function prettify(caption, deps) {
  const list = deps.map(dep => `* ${dep}`);
  return list.length ? [caption].concat(list) : [];
}

function print(result, log, json) {
  if (json) {
    log(JSON.stringify(result, (key, value) => lodash.isError(value) ? value.stack : value));
  } else if (noIssue(result)) {
    log('No depcheck issue');
  } else {
    const deps = prettify('Unused dependencies', result.dependencies);
    const devDeps = prettify('Unused devDependencies', result.devDependencies);
    const missing = prettify('Missing dependencies', Object.keys(result.missing));
    const content = deps.concat(devDeps, missing).join('\n');
    log(content);
  }

  return result;
}

export default function cli(args, log, error, exit) {
  const opt = yargs(args)
    .usage('Usage: $0 [DIRECTORY]')
    .boolean([
      'dev',
      'ignore-bin-package',
    ])
    .default({
      dev: true,
      'ignore-bin-package': false,
    })
    .describe('dev', 'Check on devDependecies')
    .describe('ignore-bin-package', 'Ignore package with bin entry')
    .describe('json', 'Output results to JSON')
    .describe('ignores', 'Comma separated package list to ignore')
    .describe('ignore-dirs', 'Comma separated folder names to ignore')
    .describe('parsers', 'Comma separated glob:pasers pair list')
    .describe('detectors', 'Comma separated detector list')
    .describe('specials', 'Comma separated special parser list')
    .version('version', 'Show version number', version)
    .help('help', 'Show this help message');

  const dir = opt.argv._[0] || '.';
  const rootDir = path.resolve(dir);

  checkPathExist(rootDir)
  .catch(() => {
    error(`Path ${dir} does not exist`);
    exit(-1);
  })
  .then(() => checkPathExist(path.resolve(rootDir, 'package.json')))
  .catch(() => {
    error(`Path ${dir} does not contain a package.json file`);
    exit(-1);
  })
  .then(() => depcheck(rootDir, {
    withoutDev: !opt.argv.dev,
    ignoreBinPackage: opt.argv.ignoreBinPackage,
    ignoreMatches: (opt.argv.ignores || '').split(','),
    ignoreDirs: (opt.argv.ignoreDirs || '').split(','),
    parsers: getParsers(opt.argv.parsers),
    detectors: getDetectors(opt.argv.detectors),
    specials: getSpecials(opt.argv.specials),
  }))
  .then(result => print(result, log, opt.argv.json))
  .then(({ dependencies: deps, devDependencies: devDeps }) =>
    exit(opt.argv.json || deps.length === 0 && devDeps.length === 0 ? 0 : -1));
}

@@ -198,16 +198,30 @@
 xist(dir
+, errorMessage
 ) %7B%0A  re
@@ -315,16 +315,28 @@
  reject(
+errorMessage
 )));%0A%7D%0A%0A
@@ -2744,37 +2744,10 @@
 tDir
-)%0A  .catch(() =%3E %7B%0A    error(
+, 
 %60Pat
@@ -2771,37 +2771,19 @@
  exist%60)
-;
 %0A  
-  exit(-1);%0A  %7D)%0A
   .then(
@@ -2803,16 +2803,23 @@
 thExist(
+%0A      
 path.res
@@ -2851,38 +2851,16 @@
 on')
-))%0A  .catch(() =%3E %7B%0A    error(
+,%0A      
 %60Pat
@@ -2910,29 +2910,12 @@
 le%60)
-;%0A    exit(-1);%0A  %7D
 )%0A
+  
   .t
@@ -2948,16 +2948,18 @@
 , %7B%0A    
+  
 withoutD
@@ -2977,24 +2977,26 @@
 gv.dev,%0A    
+  
 ignoreBinPac
@@ -3028,16 +3028,18 @@
 ackage,%0A
+  
     igno
@@ -3086,24 +3086,26 @@
 t(','),%0A    
+  
 ignoreDirs: 
@@ -3140,24 +3140,26 @@
 split(','),%0A
+  
     parsers:
@@ -3193,16 +3193,18 @@
 s),%0A    
+  
 detector
@@ -3244,16 +3244,18 @@
 s),%0A    
+  
 specials
@@ -3292,14 +3292,18 @@
 s),%0A
+  
   %7D))%0A
+  
   .t
@@ -3351,16 +3351,18 @@
 .json))%0A
+  
   .then(
@@ -3411,24 +3411,26 @@
 vDeps %7D) =%3E%0A
+  
     exit(opt
@@ -3495,12 +3495,91 @@
 0 : -1))
+%0A    .catch(errorMessage =%3E %7B%0A      error(errorMessage);%0A      exit(-1);%0A    %7D)
 ;%0A%7D%0A

Change the flow about CLI output.