import { promisify } from 'node:util';
import childProcess from 'node:child_process';
import fs, { constants } from 'node:fs/promises';
import process__default from 'node:process';
import os__default from 'node:os';
import fs__default from 'node:fs';
import 'node:buffer';

let isDockerCached;

function hasDockerEnv() {
	try {
		fs__default.statSync('/.dockerenv');
		return true;
	} catch {
		return false;
	}
}

function hasDockerCGroup() {
	try {
		return fs__default.readFileSync('/proc/self/cgroup', 'utf8').includes('docker');
	} catch {
		return false;
	}
}

function isDocker() {
	// TODO: Use `??=` when targeting Node.js 16.
	if (isDockerCached === undefined) {
		isDockerCached = hasDockerEnv() || hasDockerCGroup();
	}

	return isDockerCached;
}

let cachedResult;

// Podman detection
const hasContainerEnv = () => {
	try {
		fs__default.statSync('/run/.containerenv');
		return true;
	} catch {
		return false;
	}
};

function isInsideContainer() {
	// TODO: Use `??=` when targeting Node.js 16.
	if (cachedResult === undefined) {
		cachedResult = hasContainerEnv() || isDocker();
	}

	return cachedResult;
}

const isWsl = () => {
	if (process__default.platform !== 'linux') {
		return false;
	}

	if (os__default.release().toLowerCase().includes('microsoft')) {
		if (isInsideContainer()) {
			return false;
		}

		return true;
	}

	try {
		if (fs__default.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft')) {
			return !isInsideContainer();
		}
	} catch {}

	// Fallback for custom kernels: check WSL-specific paths.
	if (
		fs__default.existsSync('/proc/sys/fs/binfmt_misc/WSLInterop')
		|| fs__default.existsSync('/run/WSL')
	) {
		return !isInsideContainer();
	}

	return false;
};

const isWsl$1 = process__default.env.__IS_WSL_TEST__ ? isWsl : isWsl();

promisify(childProcess.execFile);

const powerShellPath$1 = () => `${process__default.env.SYSTEMROOT || process__default.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;

function parseMountPointFromConfig(content) {
	for (const line of content.split('\n')) {
		// Skip comment lines
		if (/^\s*#/.test(line)) {
			continue;
		}

		// Match root at start of line (after optional whitespace)
		const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
		if (!match) {
			continue;
		}

		return match.groups.mountPoint
			.trim()
			// Strip surrounding quotes
			.replaceAll(/^["']|["']$/g, '');
	}
}

const execFile = promisify(childProcess.execFile);

const wslDrivesMountPoint = (() => {
	// Default value for "root" param
	// according to https://docs.microsoft.com/en-us/windows/wsl/wsl-config
	const defaultMountPoint = '/mnt/';

	let mountPoint;

	return async function () {
		if (mountPoint) {
			// Return memoized mount point value
			return mountPoint;
		}

		const configFilePath = '/etc/wsl.conf';

		let isConfigFileExists = false;
		try {
			await fs.access(configFilePath, constants.F_OK);
			isConfigFileExists = true;
		} catch {}

		if (!isConfigFileExists) {
			return defaultMountPoint;
		}

		const configContent = await fs.readFile(configFilePath, {encoding: 'utf8'});
		const parsedMountPoint = parseMountPointFromConfig(configContent);

		if (parsedMountPoint === undefined) {
			return defaultMountPoint;
		}

		mountPoint = parsedMountPoint;
		mountPoint = mountPoint.endsWith('/') ? mountPoint : `${mountPoint}/`;

		return mountPoint;
	};
})();

const powerShellPathFromWsl = async () => {
	const mountPoint = await wslDrivesMountPoint();
	return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
};

const powerShellPath = isWsl$1 ? powerShellPathFromWsl : powerShellPath$1;

// Cache for PowerShell accessibility check
let canAccessPowerShellPromise;

const canAccessPowerShell = async () => {
	canAccessPowerShellPromise ??= (async () => {
		try {
			const psPath = await powerShellPath();
			await fs.access(psPath, constants.X_OK);
			return true;
		} catch {
			// PowerShell is not accessible (either doesn't exist, no execute permission, or other error)
			return false;
		}
	})();

	return canAccessPowerShellPromise;
};

const isUrl = path => /^[a-z]+:\/\//i.test(path);

const convertWslPathToWindows = async paths => {
	const isBatch = Array.isArray(paths);
	const pathArray = isBatch ? paths : [paths];

	// Find indices of non-URL paths that need conversion
	const indicesToConvert = [];
	const pathsToConvert = [];

	for (const [index, path] of pathArray.entries()) {
		if (!isUrl(path)) {
			indicesToConvert.push(index);
			pathsToConvert.push(path);
		}
	}

	// Start with original paths (URLs stay as-is)
	const results = [...pathArray];

	if (pathsToConvert.length > 0) {
		try {
			const {stdout} = await execFile('wslpath', ['-aw', ...pathsToConvert], {encoding: 'utf8'});
			const convertedPaths = stdout.split(/\r?\n/).filter(Boolean);

			for (const [index, originalIndex] of indicesToConvert.entries()) {
				results[originalIndex] = convertedPaths[index] ?? pathArray[originalIndex];
			}
		} catch {
			// If wslpath fails, keep original paths
		}
	}

	return isBatch ? results : results[0];
};

const isUncPath = path => /^\\\\/u.test(path);

export { canAccessPowerShell, convertWslPathToWindows, isUncPath, isWsl$1 as isWsl, powerShellPath, powerShellPathFromWsl, wslDrivesMountPoint };
