'use strict';
import path from 'path';
import fs from 'fs';
import _ from 'lodash';
import Promise from 'bluebird';
import {exec} from 'child_process';
import helpers from 'yeoman-test';
import assert from 'yeoman-assert';
import recursiveReadDir from 'recursive-readdir';

const TEST_DIR = __dirname;

/**
 * Copy file from src to dest
 * @param {string} src
 * @param {string} dest
 * @returns {Promise}
 */
export function copyAsync(src, dest) {
  return fs.readFileAsync(src)
    .then(data => fs.writeFileAsync(dest, data));
}

/**
 * @callback doneCallback
 * @param {null|Error} err
 */

/**
 * Run the given command in a child process
 * @param {string} cmd - command to run
 * @returns {Promise}
 */
export function runCmd(cmd) {
  return new Promise((resolve, reject) => {
    exec(cmd, {maxBuffer: 1024 * 500}, function(err, stdout, stderr) {
      if(err) {
        console.error(stdout);
        return reject(err);
      } else {
        if(DEBUG) console.log(`${cmd} stdout: ${stdout}`);
        return resolve();
      }
    });
  });
}

/**
 * Assert that only the expected files are present
 * @param {string[]} expectedFiles - array of expected files
 * @param {string} [topLevelPath='./'] - root dir of expected files to recursively search
 * @param {string[]} [skip=['node_modules','bower_components']] - files/folders recursiveReadDir should skip
 * @returns {Promise}
 */
export function assertOnlyFiles(expectedFiles, topLevelPath='./', skip=['node_modules', 'bower_components']) {
  return new Promise((resolve, reject) => {
    recursiveReadDir(topLevelPath, skip, function(err, actualFiles) {
      if(err) return reject(err);

      actualFiles = _.map(actualFiles.concat(), file => path.normalize(file.replace(path.normalize(`${topLevelPath}/`), '')));
      expectedFiles = _.map(expectedFiles, file => path.normalize(file));

      let extras = _.pullAll(actualFiles, expectedFiles);

      if(extras.length !== 0) {
        return reject(extras);
      }
      resolve();
    });
  });
}

/**
 * Read JSON from a file
 * @param {string} path
 * @returns {Promise} - parsed JSON
 */
export function readJSON(path) {
  return fs.readFileAsync(path, 'utf8').then(data => {
    return JSON.parse(data);
  });
}

/**
 * Run angular-fullstack:app
 * @param {object} [prompts]
 * @param {object} [opts={}]
 * @param {boolean} [opts.copyConfigFile] - copy default .yo-rc.json
 * @returns {Promise}
 */
export function runGen(prompts, opts={}) {
  let options = opts.options || {skipInstall: true};

  // let dir;
  let gen = helpers
    .run(require.resolve('../generators/app'))
    .inTmpDir(function(dir) {
      // this will create a new temporary directory for each new generator run
      var done = this.async();
      if(DEBUG) console.log(`TEMP DIR: ${dir}`);

      let promises = [
        fs.symlinkAsync(__dirname + '/fixtures/node_modules', dir + '/node_modules')
      ];

      if(opts.copyConfigFile) {
        promises.push(copyAsync(path.join(TEST_DIR, 'fixtures/.yo-rc.json'), path.join(dir, '.yo-rc.json')));
      }

      // symlink our dependency directories
      return Promise.all(promises).then(done);
    })
    .withGenerators([
      require.resolve('../generators/endpoint'),
      // [helpers.createDummyGenerator(), 'ng-component:app']
    ])
    // .withArguments(['upperCaseBug'])
    .withOptions(options);

  if(prompts) gen.withPrompts(prompts);

  return gen.toPromise();
}
