import { execSync } from 'node:child_process';
import process from 'node:process';
import { styleText } from 'node:util';
import { DEFAULT_PACKAGE_MANAGER, type PACKAGE_MANAGERS } from '../util/constants.js';

/**
 * A union of supported package managers.
 */
export type PackageManager = (typeof PACKAGE_MANAGERS)[number];

/**
 * Resolves the package manager from `npm_config_user_agent`.
 */
export function resolvePackageManager(): PackageManager {
	const npmConfigUserAgent = process.env.npm_config_user_agent;

	// @ts-expect-error: We're not using Deno's types, so its global is not declared
	if (typeof Deno !== 'undefined') {
		return 'deno';
	}

	if (process.versions.bun) {
		return 'bun';
	}

	// If this is not present, return the default package manager.
	if (!npmConfigUserAgent) {
		return DEFAULT_PACKAGE_MANAGER;
	}

	if (npmConfigUserAgent.startsWith('npm')) {
		return 'npm';
	}

	if (npmConfigUserAgent.startsWith('yarn')) {
		return 'yarn';
	}

	if (npmConfigUserAgent.startsWith('pnpm')) {
		return 'pnpm';
	}

	if (npmConfigUserAgent.startsWith('bun')) {
		return 'bun';
	}

	console.error(
		styleText(
			'yellow',
			`Detected an unsupported package manager (${npmConfigUserAgent}). Falling back to ${DEFAULT_PACKAGE_MANAGER}.`,
		),
	);

	// Fallback to the default package manager.
	return DEFAULT_PACKAGE_MANAGER;
}

/**
 * Installs with a provided package manager.
 *
 * @param packageManager - The package manager to use
 */
export function install(packageManager: PackageManager) {
	let installCommand: string[] | string = `${packageManager} install`;

	console.log(`Installing dependencies with ${packageManager}...`);

	// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
	switch (packageManager) {
		case 'yarn':
			console.log();
			installCommand = [
				`${packageManager} set version stable`,
				`${packageManager} config set nodeLinker node-modules`,
				`${packageManager} config set logFilters --json '[{ "code": "YN0002", "level": "discard" }, { "code": "YN0013", "level": "discard" }, { "code": "YN0032", "level": "discard" }, { "code": "YN0060", "level": "discard" }]'`,
				`${packageManager} plugin import interactive-tools`,
				`${packageManager} plugin import workspace-tools`,
				installCommand,
			];
			break;
		case 'deno':
			installCommand = `${packageManager} cache --reload src/index.ts`;
			break;
		case 'pnpm':
		case 'bun':
			console.log();
			break;
		default:
			break;
	}

	const env = {
		...process.env,
		ADBLOCK: '1',
		NODE_ENV: 'development',
		DISABLE_OPENCOLLECTIVE: '1',
	};

	if (Array.isArray(installCommand)) {
		for (const [index, command] of installCommand.entries()) {
			if (index === installCommand.length - 1) {
				execSync(command, {
					stdio: 'inherit',
					env,
				});

				break;
			}

			execSync(command, {
				stdio: 'ignore',
				env,
			});
		}

		return;
	}

	execSync(installCommand, {
		stdio: 'inherit',
		env,
	});
}
