const nexe = require('nexe');
const monkeyPatch = require('nexe/lib/monkeypatch');
const fs = require('fs');
const path = require('path');
const os = require('os');
const zlib = require('zlib');
const embed = require('./embed');

const nodeVersion = '8.4.0';

function getDirContents(dir, accumPath = dir) {
  let filenames = fs.readdirSync(dir);

  return filenames.reduce((ret, filename) => {
    const fname = path.resolve(accumPath, filename);
    const fStat = fs.statSync(fname);

    if (fStat.isDirectory()) {
      const newAccum = path.join(accumPath, filename);
      return ret.concat(getDirContents(newAccum, newAccum));
    }

    ret.push(path.join(accumPath, filename));
    return ret;
  }, []);
}

function deflate(fname) {
  return new Promise((resolve, reject) => {
    fs.readFile(fname, (err, input) => {
      fs.writeFileSync(fname, zlib.deflateSync(input));
      resolve();
    });
  });
}

const outputPath = `build/${/^Windows/.test(os.type()) ? 'lumo.exe' : 'lumo'}`;
const resources = getDirContents('target').filter(
  fname =>
    fname.endsWith('.aot.js.map') ||
    !fname.endsWith('main.js') &&
    !fname.endsWith('bundle.js') &&
    !fname.endsWith('bundle.min.js') &&
    !fname.endsWith('google-closure-compiler-js.js') &&
    !fname.endsWith('aot.edn') &&
    !/target[\\\/]cljs[\\/]core.js/.test(fname) &&
    !fname.endsWith('.map'),
);

function moveLibs(compiler, options, callback) {
  fs.writeFileSync(
    `${compiler.dir}/google-closure-compiler-js.js`,
    fs.readFileSync(`target/google-closure-compiler-js.js`),
  );

  callback(null, compiler, options);
}

function patchVCBuild(compiler, options, callback) {
  const vcbuildPath = path.join(compiler.dir, 'vcbuild.bat');

  monkeyPatch(
    vcbuildPath,
    function(content) {
      return ~content.indexOf('withsnapshot');
    },
    function(content, next) {
      const newContent = content
        .replace(
          'set nosnapshot=',
          `set nosnapshot=
set withsnapshot=`,
        )
        .replace(
          'if /i "%1"=="nosnapshot"    set nosnapshot=1&goto arg-ok',
          `if /i "%1"=="nosnapshot"    set nosnapshot=1&goto arg-ok
if /i "%1"=="withsnapshot"    set withsnapshot=1&goto arg-ok`,
        )
        .replace(
          'if defined nosnapshot set configure_flags=%configure_flags% --without-snapshot',
          `if defined nosnapshot set configure_flags=%configure_flags% --without-snapshot
if defined withsnapshot set configure_flags=%configure_flags% --with-snapshot`,
        );
      next(null, newContent);
    },
    callback,
  );
}

Promise.all(resources.map(deflate)).then(() => {
  embed(resources, 'target');

  nexe.compile(
    {
      input: 'target/bundle.min.js',
      output: outputPath,
      nodeTempDir: 'tmp',
      patchFns: [moveLibs, patchVCBuild],
      nodeConfigureArgs: [
        '--without-dtrace',
        '--without-npm',
        '--without-inspector',
        '--without-etw',
        '--without-perfctr',
        '--with-snapshot',
        '--link-module',
        './google-closure-compiler-js.js',
      ],
      nodeMakeArgs: ['-j', '8'],

      nodeVCBuildArgs: ['nosign', 'x64', 'noetw', 'noperfctr', 'withsnapshot'],
      flags: true,
      startupSnapshot: 'target/main.js',
      noBundle: true,
      framework: 'node',
      nodeVersion,
    },
    err => {
      if (err) {
        throw err;
      }
      console.log(
        `Finished bundling. Nexe binary can be found in ${outputPath}`,
      );
    },
  );
});

@@ -27,61 +27,8 @@
 ');%0A
-const monkeyPatch = require('nexe/lib/monkeypatch');%0A
 cons
@@ -193,17 +193,17 @@
 on = '8.
-4
+5
 .0';%0A%0Afu
@@ -1036,24 +1036,25 @@
 ap') %7C%7C%0A    
+(
 !fname.endsW
@@ -1063,32 +1063,34 @@
 h('main.js') &&%0A
+  
     !fname.endsW
@@ -1105,32 +1105,34 @@
 dle.js') &&%0A    
+ 
+ 
 !fname.endsWith(
@@ -1143,32 +1143,34 @@
 dle.min.js') &&%0A
+  
     !fname.endsW
@@ -1205,32 +1205,34 @@
 -js.js') &&%0A    
+ 
+ 
 !fname.endsWith(
@@ -1241,24 +1241,26 @@
 ot.edn') &&%0A
+  
     !/target
@@ -1298,24 +1298,26 @@
 ame) &&%0A    
+  
 !fname.endsW
@@ -1327,16 +1327,17 @@
 ('.map')
+)
 ,%0A);%0A%0Afu
@@ -1538,1003 +1538,8 @@
 ack(
-null, compiler, options);%0A%7D%0A%0Afunction patchVCBuild(compiler, options, callback) %7B%0A  const vcbuildPath = path.join(compiler.dir, 'vcbuild.bat');%0A%0A  monkeyPatch(%0A    vcbuildPath,%0A    function(content) %7B%0A      return ~content.indexOf('withsnapshot');%0A    %7D,%0A    function(content, next) %7B%0A      const newContent = content%0A        .replace(%0A          'set nosnapshot=',%0A          %60set nosnapshot=%0Aset withsnapshot=%60,%0A        )%0A        .replace(%0A          'if /i %22%251%22==%22nosnapshot%22    set nosnapshot=1&goto arg-ok',%0A          %60if /i %22%251%22==%22nosnapshot%22    set nosnapshot=1&goto arg-ok%0Aif /i %22%251%22==%22withsnapshot%22    set withsnapshot=1&goto arg-ok%60,%0A        )%0A        .replace(%0A          'if defined nosnapshot set configure_flags=%25configure_flags%25 --without-snapshot',%0A          %60if defined nosnapshot set configure_flags=%25configure_flags%25 --without-snapshot%0Aif defined withsnapshot set configure_flags=%25configure_flags%25 --with-snapshot%60,%0A        );%0A      next(null, newContent);%0A    %7D,%0A    callback,%0A  
 );%0A%7D
@@ -1747,17 +1747,16 @@
 tchFns: 
-%5B
 moveLibs
@@ -1760,23 +1760,8 @@
 ibs,
- patchVCBuild%5D,
 %0A   
@@ -2059,17 +2059,16 @@
 , '8'%5D,%0A
-%0A
       no
@@ -2124,24 +2124,8 @@
 ctr'
-, 'withsnapshot'
 %5D,%0A 

Upgrade Node.js to 8.5.0