var yaml = require('js-yaml');

module.exports.getDiag = function (body) {
    var yamlStart = body.indexOf('  ---');
    var yamlEnd = body.indexOf('  ...\n');
    var diag = body.slice(yamlStart, yamlEnd).split('\n').map(function (line) {
        return line.slice(2);
    }).join('\n');

    // The stack trace will vary depending on where the code is run, so just
    // strip it out.
    var withStack = yaml.safeLoad(diag);
    delete withStack.stack;
    return withStack;
}

// There are three challenges associated with checking the stack traces included
// in errors:
// 1) The base checkout directory of tape might change. Because stack traces
//    include absolute paths, the stack traces will change depending on the
//    checkout path. We handle this by replacing the base test directory with a
//    placeholder $TEST variable.
// 2) Line positions within the file might change. We handle this by replacing
//    line and column markers with placeholder $LINE and $COL "variables"
//   a) node 0.8 does not provide nested eval line numbers, so we remove them
// 3) Stacks themselves change frequently with refactoring. We've even run into
//    issues with node library refactorings "breaking" stack traces. Most of
//    these changes are irrelevant to the tests themselves. To counter this, we
//    strip out all stack frames that aren't directly under our test directory,
//    and replace them with placeholders.
module.exports.stripFullStack = function (output) {
  var stripped = '          [... stack stripped ...]';
  var withDuplicates = output.split('\n').map(function (line) {
      var m = line.match(/[ ]{8}at .*\((.*)\)/);

      var stripChangingData = function (line) {
          var withoutDirectory = line.replace(__dirname, '$TEST');
          var withoutLineNumbers = withoutDirectory.replace(/:\d+:\d+/g, ':$LINE:$COL');
          var withoutNestedLineNumbers = withoutLineNumbers.replace(/, \<anonymous\>:\$LINE:\$COL\)$/, ')');
          return withoutNestedLineNumbers;
      }

      if (m) {
          if (m[1].slice(0, __dirname.length) === __dirname) {
              return stripChangingData(line);
          }
          return stripped;
      }
      return stripChangingData(line);
  })

  var deduped = withDuplicates.filter(function (line, ix) {
      var hasPrior = line === stripped && withDuplicates[ix - 1] === stripped;
      return !hasPrior;
  });

  return deduped.join('\n');
}
