var plugin = require('../plugin');
var shell = require('..');

var assert = require('assert');

shell.config.silent = true;

var data = 0;
var ret;
var fname;

function fooImplementation(options, arg) {
  // Some sort of side effect, so we know when this is called
  if (arg) {
    fname = arg;
  } else {
    fname = plugin.readFromPipe();
  }

  if (arg === 'exitWithCode5') {
    plugin.error('Exited with code 5', 5);
  } else if (arg === 'changePrefix') {
    plugin.error('prefix was changed', {
      prefix: 'prefix: ',
    });
  } else if (arg === 'continue') {
    plugin.error('Error, but continuing', {
      continue: true,
    });
  }

  if (options.flag) {
    data = 12;
  } else {
    data++;
  }
  return 'hello world';
}

// All plugin utils exist
assert.equal(typeof plugin.error, 'function');
assert.equal(typeof plugin.parseOptions, 'function');
assert.equal(typeof plugin.readFromPipe, 'function');
assert.equal(typeof plugin.register, 'function');

// The plugin does not exist before it's registered
assert.ok(!shell.foo);

// Register the plugin
plugin.register('foo', fooImplementation, {
  cmdOptions: {
    'f': 'flag',
  },
  wrapOutput: true,
  canReceivePipe: true,
});

// The plugin exists after registering
assert.equal(typeof shell.foo, 'function');

// The command fails for invalid options
ret = shell.foo('-n', 'filename');
assert.equal(ret.code, 1);
assert.equal(ret.stdout, '');
assert.equal(ret.stderr, 'foo: option not recognized: n');
assert.equal(shell.error(), 'foo: option not recognized: n');

// The command succeeds for normal calls
assert.equal(data, 0);
shell.foo('filename');
assert.equal(data, 1);
assert.equal(fname, 'filename');
shell.foo('filename2');
assert.equal(data, 2);
assert.equal(fname, 'filename2');

// The command parses options
shell.foo('-f', 'filename');
assert.equal(data, 12);
assert.equal(fname, 'filename');

// The command supports globbing by default
shell.foo('-f', 're*u?ces');
assert.equal(data, 12);
assert.equal(fname, 'resources');

// Plugins are also compatible with shelljs/global
require('../global');
assert.equal(typeof global.foo, 'function');
assert.equal(global.foo, shell.foo);

// Plugins can be added as methods to ShellStrings
ret = shell.ShellString('hello world\n');
assert.equal(ret.toString(), 'hello world\n');
assert.equal(typeof ret.grep, 'function'); // existing methods persist
assert.equal(typeof ret.foo, 'function');
ret.foo();
assert.equal(fname, 'hello world\n'); // readFromPipe() works

// Plugins can signal errors
ret = shell.foo('exitWithCode5');
assert.equal(ret.code, 5);
assert.equal(ret.stdout, '');
assert.equal(ret.stderr, 'foo: Exited with code 5');
assert.equal(shell.error(), 'foo: Exited with code 5');

// Plugins can change the prefix
ret = shell.foo('changePrefix');
assert.equal(ret.code, 1);
assert.equal(ret.stdout, '');
assert.equal(ret.stderr, 'prefix: prefix was changed');
assert.equal(shell.error(), 'prefix: prefix was changed');

// Plugins can continue from errors
ret = shell.foo('continue');
assert.equal(ret.code, 1);
assert.equal(ret.stdout, 'hello world');
assert.equal(ret.stderr, 'foo: Error, but continuing');
assert.equal(shell.error(), 'foo: Error, but continuing');

// Cannot overwrite an existing command by default
var oldCat = shell.cat;
assert.throws(function () {
  plugin.register('cat', fooImplementation);
}, 'Error: unable to overwrite `cat` command');
assert.equal(shell.cat, oldCat);

shell.exit(123);
