import co from 'co';
import path from 'path';
import fs from 'fs';
import globby from 'globby';
import actionInterfaceTest from './_common-action-interface-check';
import addFile from './_common-action-add-file';

export default co.wrap(function* (data, cfg, plop) {
	const cfgWithCommonInterface = Object.assign({}, cfg, {
		path: cfg.destination
	});
	const interfaceTestResult = actionInterfaceTest(cfgWithCommonInterface);
	if (interfaceTestResult !== true) { throw interfaceTestResult; }

	if (cfg.base) {
		cfg.base = plop.renderString(cfg.base, data);
	}
	if(typeof cfg.templateFiles === 'function'){
		cfg.templateFiles = cfg.templateFiles();
	}
	cfg.templateFiles = []
		// Ensure `cfg.templateFiles` is an array, even if a string is passed.
		.concat(cfg.templateFiles)
		.map((file) => plop.renderString(file, data));

	const templateFiles = resolveTemplateFiles(cfg.templateFiles, cfg.base, cfg.globbyOptions, plop);
   
	const filesAdded = [];
	for (let templateFile of templateFiles) {
		const fileCfg = Object.assign({}, cfg, {
			path: resolvePath(cfg.destination, templateFile, cfg.base),
			templateFile: templateFile
		});
		const addedPath = yield addFile(data, fileCfg, plop);
		filesAdded.push(addedPath);
	}

	return `${filesAdded.length} files added\n -> ${filesAdded.join('\n -> ')}`;
});

function resolveTemplateFiles(templateFilesGlob, basePath,globbyOptions, plop) {
	globbyOptions = Object.assign({ cwd: plop.getPlopfilePath() },globbyOptions);
	return globby.sync(templateFilesGlob, globbyOptions)
		.filter(isUnder(basePath))
		.filter(isAbsoluteOrRelativeFileTo(plop.getPlopfilePath()));
}
function isAbsoluteOrRelativeFileTo(relativePath) {
	const isFile = file => fs.existsSync(file) && fs.lstatSync(file).isFile();
	return file => isFile(file) || isFile(path.join(relativePath,file));
}

function isUnder(basePath = '') {
	return (path) => path.startsWith(basePath);
}

function resolvePath(destination, file, rootPath) {
	return toUnix(path.join(destination, dropFileRootPath(file, rootPath)));
}

function toUnix(path) {
	return !path.sep || path.sep === '\\'  ? path.replace(/\\/g, '/') : path;
}

function dropFileRootPath(file, rootPath) {
	return (rootPath) ? file.replace(rootPath, '') : dropFileRootFolder(file);
}

function dropFileRootFolder(file) {
	const fileParts = path.normalize(file).split(path.sep);
	fileParts.shift();

	return fileParts.join(path.sep);
}

@@ -265,92 +265,88 @@
  %7B%0A%09
-const cfgWithCommonInterface = Object.assign(%7B%7D, cfg, %7B%0A%09%09
+// check the common action interface attributes. skip 
 path
-:
  c
-fg.destination%0A%09%7D);
+heck because it's NA
 %0A%09co
@@ -398,27 +398,28 @@
 (cfg
-WithCommonInterface
+, %7BcheckPath: false%7D
 );%0A%09
@@ -482,16 +482,205 @@
 esult; %7D
+%0A%09// check that destination (instead of path) is a string value%0A%09const dest = cfg.destination;%0A%09if (typeof dest !== 'string' %7C%7C dest.length === 0) %7B throw %60Invalid destination %22$%7Bdest%7D%22%60; %7D
 %0A%0A%09if (c
@@ -741,16 +741,17 @@
 ta);%0A%09%7D%0A
+%0A
 %09if(type
@@ -834,16 +834,17 @@
 s();%0A%09%7D%0A
+%0A
 %09cfg.tem
@@ -861,16 +861,43 @@
  = %5B%5D%0A%09%09
+.concat(cfg.templateFiles) 
 // Ensur
@@ -963,37 +963,8 @@
 ed.%0A
-%09%09.concat(cfg.templateFiles)%0A
 %09%09.m
@@ -1007,16 +1007,53 @@
  data));
+ // render the paths as hbs templates
 %0A%0A%09const
@@ -1149,11 +1149,8 @@
 p);%0A
-   
 %0A%09co

restructure common interface check so that errors reference correct attribute names