#pragma once
/*
 * Run tools/jsc-npm-bundle/bundle.mjs (esbuild) before ModuleResolver when
 * bundleDependencies / -bundle-npm is enabled.
 */

#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <sstream>
#include <stdexcept>
#include <string>

#ifndef _WIN32
#include <sys/wait.h>
#endif

namespace fs = std::filesystem;

namespace jsc_npm_bundle {

inline bool shellCommandFailed(int st) {
#ifdef _WIN32
    return st != 0;
#else
    if (st == -1)
        return true;
    if (!WIFEXITED(st))
        return true;
    return WEXITSTATUS(st) != 0;
#endif
}

inline std::string shSingleQuote(const std::string& s) {
    std::string out = "'";
    for (char c : s) {
        if (c == '\'')
            out += "'\\''";
        else
            out += c;
    }
    out += '\'';
    return out;
}

inline void run(const std::string& binDirectory, const std::string& entryAbs,
                const std::string& projectRootAbs, const std::string& outAbs,
                const std::string& platform) {
    fs::path scriptRel =
        fs::path(binDirectory) / "tools" / "jsc-npm-bundle" / "bundle.mjs";
    if (!fs::exists(scriptRel)) {
        throw std::runtime_error(
            "blue: missing npm bundle script at " +
            fs::absolute(scriptRel).generic_string() +
            "\n  Expected tools/jsc-npm-bundle beside the compiler binary.");
    }
    fs::path marker = fs::path(binDirectory) / "tools" / "jsc-npm-bundle" /
                      "node_modules" / "esbuild" / "package.json";
    if (!fs::exists(marker)) {
        throw std::runtime_error(
            "blue: esbuild not installed.\n"
            "  From the compiler repo root run:  make tools-deps\n"
            "  Then retry.");
    }

    const char* nodeExe = std::getenv("BLUE_NODE");
    std::string node = (nodeExe && nodeExe[0]) ? std::string(nodeExe) : "node";

    std::ostringstream probe;
    probe << node << " --version >/dev/null 2>&1";
    int prc = std::system(probe.str().c_str());
    if (shellCommandFailed(prc)) {
        throw std::runtime_error(
            "blue: '" + node +
            "' failed (install Node.js or set BLUE_NODE to the node binary). "
            "Required for npm dependency bundling.");
    }

    fs::path script = fs::absolute(scriptRel);
    std::ostringstream cmd;
    cmd << node << " " << shSingleQuote(script.generic_string()) << " "
        << shSingleQuote(entryAbs) << " " << shSingleQuote(projectRootAbs) << " "
        << shSingleQuote(outAbs) << " " << shSingleQuote(platform);

    int rc = std::system(cmd.str().c_str());
    if (shellCommandFailed(rc)) {
        throw std::runtime_error(
            "blue: npm dependency bundling failed (esbuild). "
            "Check stderr and project imports/package.json.");
    }
}

}  // namespace jsc_npm_bundle
