var goog = global.goog = {};

var SHADOW_ROOTS = ["goog"];
var SHADOW_IMPORTED = global.SHADOW_IMPORTED = {};
var PATH = require("path");
var VM = require("vm");
var FS = require("fs");

// extract [root] for all goog.provide('[root].something');
// we need to pull them into local scope for every eval
var SHADOW_EXTRACT_ROOTS = function(js) {
  var re = /goog.provide\(([^)]+)\);/g
  var match = null;
  while (match = re.exec(js)) {
    var provide = match[1];
    var end = provide.indexOf('.');
    if (end == -1) {
      end = provide.length - 1;
    }

    // skip first char as match will be "cljs.core" or 'cljs.core' but always with quotes
    // end at either the first dot or end of provide-1 for one-segement namespaces
    var root = provide.substring(1, end);

    if (!SHADOW_ROOTS.includes(root)) {
      global[root] = {};
      SHADOW_ROOTS.push(root);
    }
  }
};

var SHADOW_PROVIDE = function(name) {
  return goog.exportPath_(name, undefined);
};

var SHADOW_REQUIRE = function(name) {
  return true;
};

var SHADOW_WRAP = function(js) {
  var code = "(function (require, module, __filename, __dirname) {\n";
  // this is part of goog/base.js and for some reason the only global var not on goog or goog.global
  code += "var COMPILED = false;\n"
  code += js;
  code += "\n});";
  return code;
};

var SHADOW_WRAP_OFFSET = function() {
  // -1 because we have one more lines than original (the wrapper above)
  return (2 + SHADOW_ROOTS.length) * -1;
};

var SHADOW_IMPORT = global.SHADOW_IMPORT = function(src) {
  if (CLOSURE_DEFINES["shadow.debug"]) {
    console.info("SHADOW load:", src);
  }

  SHADOW_IMPORTED[src] = true;

  // NODE_INCLUDE_PATH points to an absolute path, injected by shadow/cljs/node.clj
  var filePath = SHADOW_IMPORT_PATH + '/' + src;

  var js = FS.readFileSync(filePath);

  SHADOW_EXTRACT_ROOTS(js);
  var code = SHADOW_WRAP(js);

  var fn = VM.runInThisContext(code,
    {filename: filePath,
     lineOffset: SHADOW_WRAP_OFFSET(),
     displayErrors: true
     });

  // the comment is for source-map-support which unfortunately shows the wrong piece of code but the stack is correct
  try {
  /* ignore this, look at stacktrace */ fn.call(global, require, module, __filename, __dirname);
  } catch (e) {
    console.error("SHADOW import error", filePath);
    throw e;
  }

  return true;
};

global.SHADOW_NODE_EVAL = function(js, smJson) {
  SHADOW_EXTRACT_ROOTS(js);

  if (smJson) {
    js += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,";
    js += new Buffer(smJson).toString('base64');
  }

  // console.log(js);

  return VM.runInThisContext.call(global, js,
    {filename: "<eval>",
     lineOffset: SHADOW_WRAP_OFFSET(),
     displayErrors: true});
};
