"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "default", {
    enumerable: true,
    get: function() {
        return worker;
    }
});
var _crossspawncb = /*#__PURE__*/ _interop_require_default(require("cross-spawn-cb"));
var _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
var _noderesolveversions = /*#__PURE__*/ _interop_require_default(require("node-resolve-versions"));
var _nodeversionutils = require("node-version-utils");
var _path = /*#__PURE__*/ _interop_require_default(require("path"));
var _queuecb = /*#__PURE__*/ _interop_require_default(require("queue-cb"));
var _resolvebinsync = /*#__PURE__*/ _interop_require_default(require("resolve-bin-sync"));
var _spawnstreaming = /*#__PURE__*/ _interop_require_default(require("spawn-streaming"));
var _spawnterm = require("spawn-term");
var _compatts = require("./compat.js");
var _constantsts = require("./constants.js");
var _loadNodeVersionInstallts = /*#__PURE__*/ _interop_require_default(require("./lib/loadNodeVersionInstall.js"));
var _resolveSystemBinaryts = require("./lib/resolveSystemBinary.js");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
var isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE);
var NODE = isWindows ? 'node.exe' : 'node';
// Parse npm-generated .cmd wrapper to extract the JS script path
function parseNpmCmdWrapper(cmdPath) {
    try {
        var content = _fs.default.readFileSync(cmdPath, 'utf8');
        // Match: "%_prog%"  "%dp0%\node_modules\...\cli.js" %*
        // or: "%_prog%"  "%dp0%\path\to\script.js" %*
        var match = content.match(/"%_prog%"\s+"?%dp0%\\([^"]+)"?\s+%\*/);
        if (match) {
            var relativePath = match[1];
            var cmdDir = _path.default.dirname(cmdPath);
            return _path.default.join(cmdDir, relativePath);
        }
    } catch (_e) {
    // ignore
    }
    return null;
}
// On Windows, resolve npm bin commands to their JS entry points to bypass .cmd wrappers
// This fixes issues with nvm-windows where .cmd wrappers use symlinked node.exe directly
function resolveCommand(command, args) {
    if (!isWindows) return {
        command: command,
        args: args
    };
    // Case 1: Command is a .cmd file path
    if ((0, _compatts.stringEndsWith)(command.toLowerCase(), '.cmd')) {
        var scriptPath = parseNpmCmdWrapper(command);
        if (scriptPath) {
            return {
                command: NODE,
                args: [
                    scriptPath
                ].concat(args)
            };
        }
    }
    // Case 2: Try to resolve the command as an npm package bin from node_modules
    try {
        var binPath = (0, _resolvebinsync.default)(command);
        return {
            command: NODE,
            args: [
                binPath
            ].concat(args)
        };
    } catch (_e) {
    // Not an npm package bin, use original command
    }
    return {
        command: command,
        args: args
    };
}
function worker(versionExpression, command, args, options, callback) {
    // Handle "system" as a special version that uses system binaries directly
    if (versionExpression === 'system') {
        runWithSystemBinaries(command, args, options, callback);
        return;
    }
    // Load node-version-install lazily
    (0, _loadNodeVersionInstallts.default)(function(loadErr, installVersion) {
        if (loadErr) return callback(loadErr);
        (0, _noderesolveversions.default)(versionExpression, options, function(err, versions) {
            if (err) return callback(err);
            if (!versions.length) {
                callback(new Error("No versions found from expression: ".concat(versionExpression)));
                return;
            }
            var installOptions = (0, _compatts.objectAssign)({
                storagePath: _constantsts.storagePath
            }, options);
            var streamingOptions = options;
            var results = [];
            var queue = new _queuecb.default(1);
            // Create session once for all processes (only if multiple versions)
            var interactive = options.interactive !== false;
            var session = versions.length >= 2 && _spawnterm.createSession && !streamingOptions.streaming ? (0, _spawnterm.createSession)({
                header: "".concat(command, " ").concat(args.join(' ')),
                showStatusBar: true,
                interactive: interactive
            }) : null;
            versions.forEach(function(version) {
                queue.defer(function(cb) {
                    installVersion(version, installOptions, function(err, installs) {
                        var next = function next(err, res) {
                            if (err && err.message.indexOf('ExperimentalWarning') >= 0) {
                                res = err;
                                err = null;
                            }
                            results.push({
                                install: install,
                                command: command,
                                version: version,
                                error: err,
                                result: res
                            });
                            cb();
                        };
                        var install = installs && installs.length === 1 ? installs[0] : null;
                        if (err || !install) {
                            var error = err || new Error("Unexpected version results for version ".concat(version, ". Install ").concat(JSON.stringify(installs)));
                            results.push({
                                install: install,
                                command: command,
                                version: version,
                                error: error,
                                result: null
                            });
                            return cb();
                        }
                        var spawnOptions = (0, _nodeversionutils.spawnOptions)(install.installPath, options);
                        var prefix = install.version;
                        // On Windows, resolve npm bin commands to bypass .cmd wrappers
                        var resolved = resolveCommand(command, args);
                        if (versions.length < 2) {
                            // Show command when running single version (no terminal session, unless silent)
                            if (!options.silent) console.log("$ ".concat((0, _spawnterm.formatArguments)([
                                resolved.command
                            ].concat(resolved.args)).join(' ')));
                            return (0, _crossspawncb.default)(resolved.command, resolved.args, spawnOptions, next);
                        }
                        if (session) session.spawn(resolved.command, resolved.args, spawnOptions, {
                            group: prefix,
                            expanded: streamingOptions.expanded
                        }, next);
                        else (0, _spawnstreaming.default)(resolved.command, resolved.args, spawnOptions, {
                            prefix: prefix
                        }, next);
                    });
                });
            });
            queue.await(function(err) {
                if (session) {
                    session.waitAndClose(function() {
                        err ? callback(err) : callback(null, results);
                    });
                } else {
                    err ? callback(err) : callback(null, results);
                }
            });
        });
    });
}
/**
 * Run command using system binaries (bypassing nvu version management)
 * This handles the "system" version specifier
 */ function runWithSystemBinaries(command, args, options, callback) {
    // Find the system binary for the command
    var systemBinary = (0, _resolveSystemBinaryts.resolveSystemBinary)(command);
    if (!systemBinary) {
        callback(new Error("System ".concat(command, " not found in PATH")));
        return;
    }
    // Create spawn options with PATH excluding ~/.nvu/bin
    // This ensures any child processes also use system binaries
    var cleanPath = (0, _resolveSystemBinaryts.getPathWithoutNvuBin)();
    var spawnOptions = (0, _compatts.objectAssign)({}, options);
    spawnOptions.env = (0, _compatts.objectAssign)({}, process.env);
    spawnOptions.env.PATH = cleanPath;
    spawnOptions.stdio = options.stdio || 'inherit';
    // On Windows, resolve npm bin commands to bypass .cmd wrappers
    var resolved = resolveCommand(command, args);
    // For system, use the resolved system binary path
    var finalCommand = resolved.command === command ? systemBinary : resolved.command;
    var finalArgs = resolved.command === command ? args : resolved.args;
    if (!options.silent) {
        console.log("$ ".concat((0, _spawnterm.formatArguments)([
            finalCommand
        ].concat(finalArgs)).join(' ')));
    }
    (0, _crossspawncb.default)(finalCommand, finalArgs, spawnOptions, function(err, res) {
        if (err && err.message && err.message.indexOf('ExperimentalWarning') >= 0) {
            res = err;
            err = null;
        }
        var result = {
            install: null,
            command: command,
            version: 'system',
            error: err,
            result: res
        };
        callback(err, [
            result
        ]);
    });
}
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }