import path from 'path';
import chalk from 'chalk';
import {normalizePackageName, getShorthandName} from './plugin-naming';
import {WhitespacePluginError, MissingPluginError} from './plugin-errors';
import {PluginRecords} from '@commitlint/types';

export default function loadPlugin(
	plugins: PluginRecords,
	pluginName: string,
	debug: boolean = false
): PluginRecords {
	const longName = normalizePackageName(pluginName);
	const shortName = getShorthandName(longName);
	let plugin = null;

	if (pluginName.match(/\s+/u)) {
		throw new WhitespacePluginError(pluginName, {
			pluginName: longName,
		});
	}

	const pluginKey = longName === pluginName ? shortName : pluginName;

	if (!plugins[pluginKey]) {
		try {
			plugin = require(longName);
		} catch (pluginLoadErr) {
			try {
				// Check whether the plugin exists
				require.resolve(longName);
			} catch (error) {
				// If the plugin can't be resolved, display the missing plugin error (usually a config or install error)
				console.error(chalk.red(`Failed to load plugin ${longName}.`));

				throw new MissingPluginError(pluginName, error.message, {
					pluginName: longName,
					commitlintPath: path.resolve(__dirname, '../..'),
				});
			}

			// Otherwise, the plugin exists and is throwing on module load for some reason, so print the stack trace.
			throw pluginLoadErr;
		}

		// This step is costly, so skip if debug is disabled
		if (debug) {
			const resolvedPath = require.resolve(longName);

			let version = null;

			try {
				version = require(`${longName}/package.json`).version;
			} catch (e) {
				// Do nothing
			}

			const loadedPluginAndVersion = version
				? `${longName}@${version}`
				: `${longName}, version unknown`;

			console.log(
				chalk.blue(
					`Loaded plugin ${pluginName} (${loadedPluginAndVersion}) (from ${resolvedPath})`
				)
			);
		}

		plugins[pluginKey] = plugin;
	}

	return plugins;
}