"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkNotInstalledDependencies = exports.checkNotInstalledPlugins = void 0;
const tslib_1 = require("tslib");
const util_1 = require("util");
const child_process_1 = require("child_process");
const exec = (0, util_1.promisify)(child_process_1.exec);
const cli_ux_1 = require("cli-ux");
const console_1 = require("./console");
const checkNotInstalledPlugins = async (exercises, installedPlugins, command) => {
    var _a, e_1, _b, _c;
    console_1.default.info("Checking needed plugins...");
    const usefulExtensions = new Set(["py", "js", "jsx", "html"]);
    const foundExtensions = [];
    const testingExtensions = [];
    const neededPlugins = [];
    let someExerciseWithOnlyTestFile = false; // I will suppose that there are not exercises with only readme and test files
    // See the extensions of the files that are not tests files
    for (const e of exercises) {
        const notReadmeFiles = e.files.filter(f => !f.name.toLowerCase().includes("readme"));
        if (!someExerciseWithOnlyTestFile && notReadmeFiles.length > 0) {
            someExerciseWithOnlyTestFile = notReadmeFiles.every(f => {
                return f.name.includes("test");
            });
            if (someExerciseWithOnlyTestFile) {
                console_1.default.debug("Some exercises have only test files, I will install the @learnpack/node plugin to run the tests.");
            }
        }
        for (const f of notReadmeFiles) {
            const ext = f.name.split(".").pop();
            if (!ext)
                continue;
            if (f.name.includes("test")) {
                !testingExtensions.includes(ext) && testingExtensions.push(ext);
                continue;
            }
            if (usefulExtensions.has(ext) && !foundExtensions.includes(ext)) {
                foundExtensions.push(ext);
            }
        }
    }
    console_1.default.debug("foundExtensions", foundExtensions);
    console_1.default.debug("testingExtensions", testingExtensions);
    if (foundExtensions.length === 0 && testingExtensions.length === 0)
        return {
            needed: [],
            notInstalled: [],
        };
    if (foundExtensions.includes("html") && foundExtensions.includes("js")) {
        neededPlugins.push("@learnpack/dom");
    }
    if (foundExtensions.includes("html") && !foundExtensions.includes("js")) {
        neededPlugins.push("@learnpack/html");
    }
    if (foundExtensions.includes("jsx")) {
        neededPlugins.push("@learnpack/react");
    }
    if (foundExtensions.includes("py") || testingExtensions.includes("py")) {
        neededPlugins.push("@learnpack/python");
    }
    if ((foundExtensions.includes("js") && !foundExtensions.includes("html")) ||
        (testingExtensions.includes("js") && someExerciseWithOnlyTestFile)) {
        neededPlugins.push("@learnpack/node");
    }
    const notInstalled = neededPlugins.filter(item => !installedPlugins.includes(item));
    if (notInstalled.length > 0) {
        console_1.default.error("These plugins are not installed but required: ", notInstalled);
        const confirmInstall = await cli_ux_1.cli.confirm("Do you want to install the needed plugins? (y/n)");
        if (confirmInstall) {
            console_1.default.info("Installing the needed plugins...");
            try {
                for (var _d = true, notInstalled_1 = tslib_1.__asyncValues(notInstalled), notInstalled_1_1; notInstalled_1_1 = await notInstalled_1.next(), _a = notInstalled_1_1.done, !_a; _d = true) {
                    _c = notInstalled_1_1.value;
                    _d = false;
                    const p = _c;
                    await command.config.runCommand(`plugins:install`, [p]);
                    console_1.default.log(`Plugin ${p} installed`);
                }
            }
            catch (e_1_1) { e_1 = { error: e_1_1 }; }
            finally {
                try {
                    if (!_d && !_a && (_b = notInstalled_1.return)) await _b.call(notInstalled_1);
                }
                finally { if (e_1) throw e_1.error; }
            }
            console_1.default.log("All needed plugins installed, please restart LearnPack to load them.");
            console_1.default.info("Run: $ learnpack start");
            command.exit(0);
        }
        else {
            console_1.default.error("You need to install the plugins to complete this exercise");
            console_1.default.info("To install the plugins run each of the following commands: ");
            for (const p of notInstalled) {
                console_1.default.log(`learnpack plugins:install ${p}`);
            }
            command.exit(1);
        }
    }
    return {
        needed: neededPlugins,
        notInstalled,
    };
};
exports.checkNotInstalledPlugins = checkNotInstalledPlugins;
function includesAll(baseString, elementsArray) {
    return elementsArray.every(element => baseString.includes(element));
}
const installDependencies = async (deps, packageManager) => {
    let command = "";
    if (packageManager === "npm") {
        command = `npm install -g ${deps.join(" ")}`;
    }
    else if (packageManager === "pip") {
        command = `pip install ${deps.join(" ")}`;
    }
    try {
        const { stdout, stderr } = await exec(command);
        if (stderr &&
            (stderr.includes("npm ERR!") || stderr.includes("Traceback"))) {
            console_1.default.error(`Error executing ${command}.`);
            console_1.default.error(stderr);
            return;
        }
        console_1.default.info(`Dependencies ${deps.join(" ")} installed...`);
        return true;
    }
    catch (error) {
        // Si npm/pip retorna código > 0, exec lanzará una excepción
        const execError = error;
        const stdout = execError.stdout || "";
        const stderr = execError.stderr || "";
        const errorMessage = stderr || execError.message || String(error);
        // Verificar si es un error real
        if (errorMessage.includes("npm ERR!") ||
            errorMessage.includes("Traceback")) {
            console_1.default.error(`Error executing ${command}.`);
            console_1.default.error(errorMessage);
            return;
        }
        // Si no es un error real, podría ser solo un warning
        // Verificar si la instalación fue exitosa a pesar del warning
        if (stdout &&
            (stdout.includes("added") || stdout.includes("Successfully installed"))) {
            console_1.default.info(`Dependencies ${deps.join(" ")} installed...`);
            return true;
        }
        // Si no hay indicios de éxito, se asume fallo (retorna undefined implícitamente)
        console_1.default.debug(`${command} returned non-zero exit code, but may be just a warning:`, errorMessage);
    }
};
const checkNotInstalledDependencies = async (neededPlugins) => {
    console_1.default.info("Checking needed dependencies...");
    const jsPluginsDependencies = [
        "jest@29.7.0",
        "jest-environment-jsdom@29.7.0",
    ];
    // pytest up to 6.2.5
    const pyPluginsDependencies = ["pytest", "pytest-testdox", "mock"];
    const npmLsCommand = "npm ls jest jest-environment-jsdom -g";
    let pytestNeeded = false;
    let jestNeeded = false;
    if (neededPlugins.includes("@learnpack/dom") ||
        neededPlugins.includes("@learnpack/html") ||
        neededPlugins.includes("@learnpack/react") ||
        neededPlugins.includes("@learnpack/node")) {
        jestNeeded = true;
    }
    if (neededPlugins.includes("@learnpack/python")) {
        pytestNeeded = true;
    }
    if (jestNeeded) {
        try {
            const { stdout, stderr } = await exec("npm ls -g");
            // Solo considerar errores reales, no warnings
            if (stderr && stderr.includes("npm ERR!")) {
                console_1.default.error(`Error executing npm ls -g. Use debug for more info`);
                console_1.default.debug(stderr);
                return false;
            }
            if (includesAll(stdout, jsPluginsDependencies))
                return true;
        }
        catch (error) {
            // Si npm retorna código > 0, exec lanzará una excepción
            // Verificar si es un error real o solo un warning
            const errorMessage = (error === null || error === void 0 ? void 0 : error.stderr) || (error === null || error === void 0 ? void 0 : error.message) || String(error);
            if (errorMessage.includes("npm ERR!")) {
                console_1.default.error(`Error executing npm ls -g. Use debug for more info`);
                console_1.default.debug(errorMessage);
                return false;
            }
            // Si no es un error real, continuar (podría ser solo un warning)
            console_1.default.debug("npm ls -g returned non-zero exit code, but may be just a warning:", errorMessage);
        }
        console_1.default.error("The jest dependencies are not installed");
        const confirmInstall = await cli_ux_1.cli.confirm("Do you want to install the needed dependencies? (y/n)");
        if (!confirmInstall) {
            console_1.default.error(`The exercises can't be tested without the following dependencies: ${jsPluginsDependencies.join(", ")}`);
            console_1.default.info(`Please install them and try again. Run the following command to install them: \nnpm install -g ${jsPluginsDependencies.join(" ")}`);
            return false;
        }
        console_1.default.log("Installing jest dependencies...");
        await installDependencies(jsPluginsDependencies, "npm");
    }
    if (pytestNeeded) {
        try {
            await exec("python -m pip install --upgrade pip");
        }
        catch (error) {
            console_1.default.error("Error upgrading pip. Please install pip manually, run: pip install --upgrade pip");
            console_1.default.debug(error);
        }
        try {
            const { stdout, stderr } = await exec("pip list");
            // Solo considerar errores reales, no warnings
            if (stderr && stderr.includes("Traceback")) {
                console_1.default.error(`Error executing pip list. Use debug for more info`);
                console_1.default.debug(stderr);
                return false;
            }
            if (includesAll(stdout, pyPluginsDependencies))
                return true;
        }
        catch (error) {
            // Si pip retorna código > 0, verificar si es un error real
            const errorMessage = (error === null || error === void 0 ? void 0 : error.stderr) || (error === null || error === void 0 ? void 0 : error.message) || String(error);
            if (errorMessage.includes("Traceback")) {
                console_1.default.error(`Error executing pip list. Use debug for more info`);
                console_1.default.debug(errorMessage);
                return false;
            }
            // Si no es un error real, continuar
            console_1.default.debug("pip list returned non-zero exit code, but may be just a warning:", errorMessage);
        }
        console_1.default.error("The pytest dependencies are not installed");
        const confirmInstall = await cli_ux_1.cli.confirm("Do you want to install the needed dependencies? (y/n)");
        if (!confirmInstall) {
            console_1.default.error(`The exercises can't be tested without the following dependencies: ${pyPluginsDependencies.join(", ")}`);
            console_1.default.info(`Please install them and try again. Run the following command to install them: \npip install ${pyPluginsDependencies.join(" ")}`);
            return false;
        }
        console_1.default.log("Installing pytest dependencies...");
        await installDependencies(pyPluginsDependencies, "pip");
    }
    return true;
};
exports.checkNotInstalledDependencies = checkNotInstalledDependencies;
