#!/usr/bin/env node

const { execSync, spawn } = require('child_process');
const { readFileSync, statSync, rmdirSync } = require('fs');

// Check that the script is run from the root.

try {
  const wailsJsonFile = statSync('./wails.json');
  if (!wailsJsonFile.isFile()) {
    throw new Error();
  }
} catch {
  console.log('Error: please run the build script from the Rolens project root.');
  process.exit(1);
}

// Output version.

const version = JSON.parse(readFileSync('./wails.json').toString()).info.productVersion;

if (process.argv.includes('-v') || process.argv.includes('-version') || process.argv.includes('--version')) {
  console.log(version);
  process.exit(0);
}

// Output help text.

if (process.argv.includes('-h') || process.argv.includes('--help')) {
  console.log(`Rolens build script v${version}`);
  console.log('');
  console.log('This script installs missing dependencies if any, and then compiles Rolens');
  console.log('for the current platform.');
  console.log('');
  console.log('Options:');
  console.log('  -h --help    Show this help text and exit.');
  console.log('  -q --quiet   Do not output Wails build log.');
  console.log('  -v --version Log the current Rolens version and exit.');

  process.exit(0);
}

// Shared objects.

const quiet = process.argv.includes('-q') || process.argv.includes('--quiet');
const isWindows = process.platform === 'win32';
const missingDependencies = [];

function isNullish(val) {
  return val === undefined || val === null;
}

// Check that Go ^1.18 is installed.

try {
  const goMinorVersion = /go1\.([0-9][0-9])/.exec(
    execSync('go version').toString()
  )?.pop();

  if (isNullish(goMinorVersion) || (parseInt(goMinorVersion) < 18)) {
    throw new Error();
  }
} catch {
  missingDependencies.push({ name: 'Go ^1.18 ^16', url: 'https://go.dev/doc/install' });
}

// Check that Node.js ^16 is installed.

try {
  const nodeMajorVersion = /v([0-9]{1,2})\.[0-9]{1,3}\.[0-9]{1,3}/.exec(
    execSync('node --version').toString()
  )?.pop();

  if (isNullish(nodeMajorVersion) || (parseInt(nodeMajorVersion) < 16)) {
    throw new Error();
  }
} catch {
  missingDependencies.push({ name: 'Node.js ^16', url: 'https://go.dev/doc/install' });
}

// Check that Wails is installed.

try {
  const wailsMinorVersion = /v2\.([0-9])\.[0-9]/.exec(
    execSync('wails version').toString()
  )?.pop();

  if (isNullish(wailsMinorVersion) || (parseInt(wailsMinorVersion) < 3)) {
    throw new Error();
  }
} catch {
  missingDependencies.push({
    name: 'Wails ^2.3',
    command: 'go install github.com/wailsapp/wails/v2/cmd/wails@latest',
    url: 'https://wails.io/docs/gettingstarted/installation',
  });
}

// Check that NSIS is installed on Windows.

if (isWindows) {
  try {
    const nsisInstalled = /v3\.([0-9][0-9])/.test(execSync('makensis.exe /VERSION').toString());
    if (!nsisInstalled) {
      throw new Error();
    }
  } catch {
    missingDependencies.push({
      name: 'Nullsoft Install System ^3',
      command: 'choco install nsis',
      url: 'https://nsis.sourceforge.io/Download',
      comment: 'Note: you should add makensis.exe to your path:\n    setx /M PATH "%PATH%;C:\\Program Files (x86)\\NSIS\\Bin"'
    });
  }
}

// Report missing dependencies.

if (missingDependencies.length > 0) {
  console.log('You are missing the following dependencies:');

  for (const dependency of missingDependencies) {
    console.log('');
    console.log(`- ${dependency.name}`);

    if (dependency.command) {
      console.log('  Install it by executing:');
      console.log(`    ${dependency.command}`);
    }

    if (dependency.url) {
      console.log('  Visit the following page for more information:');
      console.log(`    ${dependency.url}`);
    }

    if (dependency.comment) {
      console.log(`  ${dependency.comment}`);
    }
  }

  process.exit(1);
}

// Clean output directory.

console.log('Cleaning output directory...');
try { rmdirSync('./build/bin'); } catch {}

// Build Rolens.

console.log(`Building Rolens ${version}...`);
console.log();

const proc = spawn('wails', [ 'build', '-clean', isWindows ? '-nsis' : '' ]);

if (!quiet) {
  proc.stdout.on('data', data => process.stdout.write(data));
  proc.stderr.on('data', data => process.stderr.write(data));
}

proc.on('exit', code => process.exit(code));
