/**
 * @license
 * Copyright 2019 Balena Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as _ from 'lodash';

import {
	buildOclifInstaller,
	buildStandaloneZip,
	catchUncommitted,
	testShrinkwrap,
} from './build-bin';
import {
	release,
	updateDescriptionOfReleasesAffectedByIssue1359,
} from './deploy-bin';
import { fixPathForMsys, ROOT, runUnderMsys } from './utils';

// DEBUG set to falsy for negative values else is truthy
process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
	process.env.DEBUG?.toLowerCase(),
)
	? ''
	: '1';

function exitWithError(error: Error | string): never {
	console.error(`Error: ${error}`);
	process.exit(1);
}

/**
 * Trivial command-line parser. Check whether the command-line argument is one
 * of the following strings, then call the appropriate functions:
 *     'build:installer'   (to build a native oclif installer)
 * 	   'build:standalone'  (to build a standalone pkg package)
 *     'release'           (to create/update a GitHub release)
 *
 * In the case of 'build:installer', also call runUnderMsys() to switch the
 * shell from cmd.exe to MSYS2 bash.exe.
 *
 * @param args Arguments to parse (default is process.argv.slice(2))
 */
export async function run(args?: string[]) {
	args = args || process.argv.slice(2);
	console.log(`automation/run.ts process.argv=[${process.argv}]\n`);
	console.log(`automation/run.ts args=[${args}]`);
	if (_.isEmpty(args)) {
		return exitWithError('missing command-line arguments');
	}
	const commands: { [cmd: string]: () => void | Promise<void> } = {
		'build:installer': buildOclifInstaller,
		'build:standalone': buildStandaloneZip,
		'catch-uncommitted': catchUncommitted,
		'test-shrinkwrap': testShrinkwrap,
		fix1359: updateDescriptionOfReleasesAffectedByIssue1359,
		release,
	};
	for (const arg of args) {
		if (!commands.hasOwnProperty(arg)) {
			return exitWithError(`command unknown: ${arg}`);
		}
	}

	// If runUnderMsys() is called to re-execute this script under MSYS2,
	// the current working dir becomes the MSYS2 homedir, so we change back.
	process.chdir(ROOT);

	// The BUILD_TMP env var is used as an alternative location for oclif
	// (patched) to copy/extract the CLI files, run npm install and then
	// create the NSIS executable installer for Windows. This was necessary
	// to avoid issues with a 260-char limit on Windows paths (possibly a
	// limitation of some library used by NSIS), as the "current working dir"
	// provided by balena CI is a rather long path to start with.
	if (process.platform === 'win32' && !process.env.BUILD_TMP) {
		const randID = (await import('crypto'))
			.randomBytes(6)
			.toString('base64')
			.replace(/\+/g, '-')
			.replace(/\//g, '_'); // base64url (RFC 4648)
		process.env.BUILD_TMP = `C:\\tmp\\${randID}`;
	}

	for (const arg of args) {
		try {
			if (arg === 'build:installer' && process.platform === 'win32') {
				// ensure running under MSYS2
				if (!process.env.MSYSTEM) {
					process.env.MSYS2_PATH_TYPE = 'inherit';
					await runUnderMsys([
						fixPathForMsys(process.argv[0]),
						fixPathForMsys(process.argv[1]),
						arg,
					]);
					continue;
				}
				if (process.env.MSYS2_PATH_TYPE !== 'inherit') {
					throw new Error(
						'the MSYS2_PATH_TYPE env var must be set to "inherit"',
					);
				}
			}
			const cmdFunc = commands[arg];
			await cmdFunc();
		} catch (err) {
			return exitWithError(`"${arg}": ${err}`);
		}
	}
}

run();