#!/usr/bin/env node

var pathIsAbsolute = require("path-is-absolute");
var commander      = require("commander");
var Module         = require("module");
var babel          = require("../lib/babel/api/node");
var path           = require("path");
var repl           = require("repl");
var util           = require("../lib/babel/util");
var vm             = require("vm");
var _              = require("lodash");

var program = new commander.Command("babel-node");

program.option("-e, --eval [script]", "Evaluate script");
program.option("-p, --print [code]", "Evaluate script and print result");
program.option("-i, --ignore [regex]", "Ignore all files that match this regex when using the require hook");
program.option("-x, --extensions [extensions]", "List of extensions to hook into [.es6,.js,.es,.jsx]");
program.option("-r, --experimental", "Enable experimental support for proposed ES7 features");
program.option("-g, --playground", "Enable playground support");
program.option("-w, --whitelist [whitelist]", "Whitelist of transformers to ONLY use", util.list);
program.option("-b, --blacklist [blacklist]", "Blacklist of transformers to NOT use", util.list);
program.option("-o, --optional [optional]", "List of optional transformers to enable", util.list);

var pkg = require("../package.json");
program.version(pkg.version);
program.usage("[options] [ -e script | script.js ] [arguments]");
program.parse(process.argv);

//

babel.register({
  experimental: program.experimental,
  extensions:   program.extensions,
  playground:   program.playground,
  blacklist:    program.blacklist,
  whitelist:    program.whitelist,
  optional:     program.optional,
  ignore:       program.ignore
});

//

var _eval = function (code, filename) {
  code = babel.transform(code, {
    filename: filename,
    blacklist: ["useStrict"].concat(program.blacklist || []),
    whitelist: program.whitelist,
    optional: program.optional,
    experimental: program.experimental,
    playground: program.playground
  }).code;

  return vm.runInThisContext(code, {
    filename: filename
  });
};

if (program.eval || program.print) {
  var code = program.eval;
  if (!code || code === true) code = program.print;

  var result = _eval(code, "eval");
  if (program.print) console.log(result);
} else {
  if (program.args.length) {
    // slice all arguments up to the first filename since they're babel args that we handle
    var args = process.argv.slice(2);

    var i = 0;
    var ignoreNext = false;
    _.each(args, function (arg, i2) {
      if (ignoreNext) {
        ignoreNext = false;
        return;
      }

      if (arg[0] === "-") {
        var parsedArg = program[arg.slice(2)];
        if (parsedArg && parsedArg !== true) {
          ignoreNext = true;
        }
      } else {
        i = i2;
        return false;
      }
    });
    args = args.slice(i);

    // make the filename absolute
    var filename = args[0]
    if (!pathIsAbsolute(filename)) args[0] = path.join(process.cwd(), filename);

    // add back on node and concat the sliced args
    process.argv = ["node"].concat(args);

    Module.runMain();
  } else {
    replStart();
  }
}

function replStart() {
  repl.start({
    prompt: "> ",
    input: process.stdin,
    output: process.stdout,
    eval: replEval,
    useGlobal: true
  });
}

function replEval(code, context, filename, callback) {
  var err;
  var result;

  try {
    if (code[0] === "(" && code[code.length - 1] === ")") {
      code = code.slice(1, -1); // remove "(" and ")"
    }

    result = _eval(code, filename);
  } catch (e) {
    err = e;
  }

  callback(err, result);
}
