'use strict';

var chalk = require('chalk');
var symbol = require('log-symbols');
var through = require('through2');
var utils = require('../utils');
var _ = require('lodash');

module.exports = function() {
  var verb = this;

  console.log(chalk.yellow('checking for conflicts'))

  return through.obj(function (file, enc, cb) {
    if (file.isNull()) {
      this.push(file);
      return cb();
    }
    if (file.isStream()) {
      this.emit('error', new utils.PluginError('conflicts plugin', 'Streaming is not supported.'));
      return cb();
    }

    var str = file.contents.toString();
    var res = helpers(str);
    var conflicting = problematic(verb, file, res);
    var h = {};

    if (!conflicting.length) {
      this.push(file);
      return cb();
    }

    var ctx = {};
    ctx.options = _.extend({}, verb.options, file.options);
    ctx.context = file.locals || {};
    ctx.app = verb;

    file.locals = file.locals || {};
    file.locals.__ = file.locals.__ || {};

    for (var i = 0; i < conflicting.length; i++) {
      var name = conflicting[i];
      file.content = namespace(file.content, name);
      var syncFn = verb._.helpers[name];
      if (syncFn) {
        h[name] = _.bind(syncFn, ctx);
        file.locals.__[name] = _.bind(syncFn, ctx);
        verb.helpers({__: h});
        delete verb._.helpers[name];
      }

      var asyncFn = verb._.asyncHelpers[name];
      if (asyncFn) {
        h[name] = _.bind(asyncFn, ctx);
        file.locals.__[name] = _.bind(asyncFn, ctx);
        verb.asyncHelpers({__: h});
        delete verb._.asyncHelpers[name];
      }

      if (!asyncFn && !syncFn) {
        h[name] = noop(name);
        file.locals.__[name] = noop(name);
        verb.helpers({__: h});
      }
    }

    file.contents = new Buffer(file.content);
    this.push(file);
    cb();
  });
};

function noop(name) {
  return function () {
    var msg = ''
    msg += 'ERROR! Cannot find the {%= ';
    msg += name;
    msg += '() %} helper. Helpers may be ';
    msg += 'registered using `verb.helper()`.';
    // console.log(chalk.red(msg));
  }
}

function namespace(str, name) {
  return str.split('{%= ' + name).join('{%= __.' + name);
}

function helpers(str) {
  var re = /\{%=\s*((?!__\.)[\w.]+)(?:\(\)|\(([^)]*?)\))\s*%}/gm;
  var res = [], match;

  while (match = re.exec(str)) {
    if (res.indexOf(match[1]) === -1) {
      res.push(match[1].trim());
    }
  }
  return res;
}

function problematic(verb, file, helpers) {
  var dataKeys = Object.keys(verb.cache.data);
  dataKeys = _.union(dataKeys, Object.keys(file.data));

  var registered = Object.keys(verb._.asyncHelpers);
  registered = _.union(registered, Object.keys(verb._.helpers));

  var h = [], d = [];
  var len = helpers.length;

  while (len--) {
    var helper = helpers[len];
    // if the helper name is also a data prop, it's a conflict
    if (dataKeys.indexOf(helper) !== -1) {
      d.push(helper);
    }

    // if the helper is not registered, it's a conflict
    if (registered.indexOf(helper) === -1) {
      h.push(helper);
    }
  }

  message(h, d);
  return _.union(h, d);
}


function message(h, d) {
  var hlen = h.length;
  var dlen = d.length;
  console.log();

  if (hlen === 0 && dlen === 0) {
    console.log(symbol.success + chalk.green('  no conflicts found.'));
    return;
  }

  if (hlen > 0) {
    console.log(symbol.error + ' ' + chalk.red(hlen + ' missing helper' + (hlen > 1 ? 's' : '') + ' found:'));
    var helpers = h.map(function (ele) {
      return ' - ' + ele + chalk.gray(' (is not registered)');
    }).join('\n');
    console.log(helpers)
    console.log();
  }

  if (dlen > 0) {
    console.log(symbol.error + ' ' + chalk.red(dlen + ' conflict' + (dlen > 1 ? 's' : '') + ' found:'));
    var props = d.map(function (ele) {
      return ' - ' + ele + chalk.gray(' (found both a helper and a data property with this name)');
    }).join('\n');
    console.log(props)
    console.log();
  }
}

@@ -221,16 +221,33 @@
  this;%0A%0A
+  console.log();%0A
   consol
@@ -266,17 +266,17 @@
 yellow('
-c
+C
 hecking 
@@ -288,19 +288,21 @@
 onflicts
+%E2%80%A6
 '))
+;
 %0A%0A  retu
@@ -412,24 +412,25 @@
 cb();%0A    %7D%0A
+%0A
     if (file
@@ -1917,16 +1917,17 @@
 msg = ''
+;
 %0A    msg
@@ -2109,16 +2109,17 @@
 g));%0A  %7D
+;
 %0A%7D%0A%0Afunc
@@ -3205,33 +3205,16 @@
 .length;
-%0A  console.log();
 %0A%0A  if (
@@ -3356,32 +3356,39 @@
     console.log(
+'  ' + 
 symbol.error + '
@@ -3613,34 +3613,16 @@
 helpers)
-%0A    console.log()
 ;%0A  %7D%0A%0A 
@@ -3650,24 +3650,31 @@
 console.log(
+'  ' + 
 symbol.error
@@ -3795,32 +3795,33 @@
 %7B%0A      return '
+ 
  - ' + ele + cha
@@ -3897,32 +3897,34 @@
 %0A    %7D).join('%5Cn
+  
 ');%0A    console.
@@ -3937,26 +3937,8 @@
 ops)
-%0A    console.log()
 ;%0A  

improve formatting for conflics plugin