import * as esbuild from 'esbuild';
import { sassPlugin } from 'esbuild-sass-plugin';
import * as fs from 'fs';
import * as path from 'path';
import { minify } from 'terser';
import { URL } from 'url';

const __dirname = new URL('.', import.meta.url).pathname.substring(1);

const args = process.argv.slice(2);

let index = args.indexOf('--mode');
const mode = (index >= 0 ? args[index + 1] : undefined) || 'none';

const watch = args.includes('--watch');
const check = !args.includes('--no-check');

/**
 * @param { 'node' | 'webworker' } target
 * @param { 'production' | 'development' | 'none' } mode
 */
async function buildExtension(target, mode) {
	let plugins = [];

	// let TypeCheckerPlugin;
	// if (check) {
	// 	({ EsbuildPlugin: TypeCheckerPlugin } = require('vite-esbuild-typescript-checker'));
	// 	plugins.push(
	// 		TypeCheckerPlugin({
	// 			checker: {
	// 				async: false,
	// 				eslint: {
	// 					enabled: true,
	// 					files: 'src/**/*.ts',
	// 					options: {
	// 						// cache: true,
	// 						cacheLocation: path.join(
	// 							__dirname,
	// 							target === 'webworker' ? '.eslintcache.browser' : '.eslintcache',
	// 						),
	// 						overrideConfigFile: path.join(
	// 							__dirname,
	// 							target === 'webworker' ? '.eslintrc.browser.json' : '.eslintrc.json',
	// 						),
	// 					},
	// 				},
	// 				formatter: 'basic',
	// 				typescript: {
	// 					configFile: target === 'webworker' ? 'tsconfig.browser.json' : 'tsconfig.json',
	// 				},
	// 			},
	// 		}),
	// 	);
	// }

	const alias = {
		'@env': path.resolve(__dirname, 'src', 'env', target === 'webworker' ? 'browser' : target),
		// This dependency is very large, and isn't needed for our use-case
		tr46: path.resolve(__dirname, 'patches', 'tr46.js'),
		// Stupid dependency that is used by `http-proxy-agent`
		debug:
			target === 'webworker'
				? path.resolve(__dirname, 'node_modules', 'debug', 'src', 'browser.js')
				: path.resolve(__dirname, 'node_modules', 'debug', 'src', 'node.js'),
	};

	if (target === 'webworker') {
		alias.path = 'path-browserify';
		alias.os = 'os-browserify/browser';
	}

	const out = target === 'webworker' ? 'dist/browser' : 'dist';

	const result = await esbuild.build({
		bundle: true,
		entryPoints: ['src/extension.ts'],
		entryNames: '[dir]/gitlens',
		alias: alias,
		drop: ['debugger'],
		external: ['vscode'],
		format: 'esm',
		keepNames: true,
		legalComments: 'none',
		logLevel: 'info',
		mainFields: target === 'webworker' ? ['browser', 'module', 'main'] : ['module', 'main'],
		metafile: true,
		minify: mode === 'production' ? true : false,
		outdir: out,
		platform: target === 'webworker' ? 'browser' : target,
		sourcemap: mode === 'production' ? false : true,
		// splitting: target === 'webworker' ? false : true,
		// chunkNames: 'feature-[name]-[hash]',
		target: ['es2022', 'chrome102', 'node16.14.2'],
		treeShaking: true,
		tsconfig: target === 'webworker' ? 'tsconfig.browser.json' : 'tsconfig.json',
		// watch: watch,
		plugins: plugins,
	});

	fs.writeFileSync(
		path.join('dist', 'meta', `gitlens${target === 'webworker' ? '.browser' : ''}.json`),
		JSON.stringify(result.metafile),
	);

	if (mode === 'production') {
		const file = path.join(out, 'gitlens.js');
		console.log(`Minifying ${file}...`);

		const code = fs.readFileSync(file, 'utf8');
		const result = await minify(code, {
			compress: {
				drop_debugger: true,
				ecma: 2020,
				module: true,
			},
			ecma: 2020,
			format: {
				comments: false,
				ecma: 2020,
			},
			// Keep the class names otherwise @log won't provide a useful name
			keep_classnames: true,
			module: true,
		});

		fs.writeFileSync(file, result.code);
	}
}

/**
 * @param { 'production' | 'development' | 'none' } mode
 */
async function buildGraphWebview(mode) {
	let plugins = [sassPlugin()];

	const out = 'dist/webviews';

	const result = await esbuild.build({
		bundle: true,
		entryPoints: ['src/webviews/apps/plus/graph/graph.tsx'],
		entryNames: '[dir]/graph',
		alias: {
			'@env': path.resolve(__dirname, 'src', 'env', 'browser'),
			tslib: path.resolve(__dirname, 'node_modules/tslib/tslib.es6.js'),
			'@microsoft/fast-foundation': path.resolve(
				__dirname,
				'node_modules/@microsoft/fast-foundation/dist/esm/index.js',
			),
			'@microsoft/fast-react-wrapper': path.resolve(
				__dirname,
				'node_modules/@microsoft/fast-react-wrapper/dist/esm/index.js',
			),
		},
		drop: ['debugger'],
		external: ['vscode'],
		format: 'esm',
		legalComments: 'none',
		logLevel: 'info',
		mainFields: ['browser', 'module', 'main'],
		metafile: true,
		minify: mode === 'production' ? true : false,
		outdir: out,
		platform: 'browser',
		sourcemap: true,
		target: ['es2022', 'chrome102'],
		treeShaking: true,
		tsconfig: 'src/webviews/apps/tsconfig.json',
		// watch: watch,
		plugins: plugins,
	});

	fs.writeFileSync(path.join('dist', 'meta', 'graph.json'), JSON.stringify(result.metafile));

	if (mode === 'production') {
		const file = path.join(out, 'graph.js');
		console.log(`Minifying ${file}...`);

		const code = fs.readFileSync(file, 'utf8');
		const result = await minify(code, {
			compress: {
				drop_debugger: true,
				ecma: 2020,
				module: true,
			},
			ecma: 2020,
			format: {
				comments: false,
				ecma: 2020,
			},
			module: true,
		});

		fs.writeFileSync(file, result.code);
	}
}

try {
	await Promise.allSettled([
		buildExtension('node', mode),
		buildExtension('webworker', mode),
		buildGraphWebview(mode),
	]);
} catch (ex) {
	console.error(ex);
	process.exit(1);
}