//compile using g++ -static -static-libgcc -static-libstdc++ b2cwrap.cpp -o b2cwrap.exe
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <filesystem>
#include <windows.h>

namespace fs = std::filesystem;

enum ConsoleColor {
    BLACK = 0,
    BLUE = 1,
    GREEN = 2,
    CYAN = 3,
    RED = 4,
    MAGENTA = 5,
    YELLOW = 6,
    WHITE = 7,
    GRAY = 8,
    LIGHT_BLUE = 9,
    LIGHT_GREEN = 10,
    LIGHT_CYAN = 11,
    LIGHT_RED = 12,
    LIGHT_MAGENTA = 13,
    LIGHT_YELLOW = 14,
    BRIGHT_WHITE = 15
};

void setColor(int color) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, color);
}

void printBanner() {
    setColor(LIGHT_CYAN);
    std::cout << "\n";
    setColor(LIGHT_YELLOW);
    std::cout << "           B2CWrap - Batch Wrapper Version 1.2\n";
    setColor(LIGHT_GREEN);
    std::cout << "           created by qaax_0\n";
    setColor(LIGHT_MAGENTA);
    std::cout << "           distributed by floppaware.neocities.org\n";
    setColor(WHITE);
    std::cout << "\n";
}

void printUsage() {
    setColor(LIGHT_YELLOW);
    std::cout << "  USAGE:\n";
    setColor(WHITE);
    std::cout << "    b2cwrap.exe <script.cmd|script.bat> [debug]\n";
    std::cout << "\n";
    setColor(LIGHT_YELLOW);
    std::cout << "  OPTIONS:\n";
    setColor(WHITE);
    std::cout << "    script.cmd|script.bat    The batch file to wrap\n";
    std::cout << "    debug                    Optional - creates debug version\n";
    std::cout << "\n";
    setColor(LIGHT_YELLOW);
    std::cout << "  EXAMPLES:\n";
    setColor(WHITE);
    std::cout << "    b2cwrap.exe my_script.bat\n";
    std::cout << "    b2cwrap.exe install.cmd debug\n";
    std::cout << "\n";
    setColor(WHITE);
}

std::string getFileName(const std::string& path) {
    fs::path p(path);
    return p.stem().string();
}

std::string readFile(const std::string& filename) {
    std::ifstream file(filename);
    if (!file.is_open()) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Could not open file: " << filename << "\n";
        setColor(WHITE);
        return "";
    }
    
    std::string content((std::istreambuf_iterator<char>(file)),
                        std::istreambuf_iterator<char>());
    file.close();
    return content;
}

bool compileWrapper(const std::string& cppPath, const std::string& exePath) {
    setColor(LIGHT_CYAN);
    std::cout << "  [*] Compiling wrapper...\n";
    setColor(WHITE);
    
    std::string compileCmd = "g++ -std=c++17 \"" + cppPath + "\" -o \"" + exePath + "\" -lstdc++fs -lole32 -lshell32 -static";
    
    int result = system(compileCmd.c_str());
    
    if (result != 0) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Compilation failed!\n";
        setColor(WHITE);
        return false;
    }
    
    setColor(LIGHT_GREEN);
    std::cout << "  [+] Compilation successful!\n";
    setColor(WHITE);
    std::cin.get();
    return true;
}

bool writeCppWrapper(const std::string& scriptPath, const std::string& outputPath, bool debugMode) {
    std::string scriptContent = readFile(scriptPath);
    if (scriptContent.empty()) {
        return false;
    }
    
    std::string escapedContent;
    for (char c : scriptContent) {
        if (c == '\\') escapedContent += "\\\\";
        else if (c == '"') escapedContent += "\\\"";
        else if (c == '\n') escapedContent += "\\n";
        else if (c == '\r') escapedContent += "\\r";
        else escapedContent += c;
    }
    
    std::string originalFilename = fs::path(scriptPath).filename().string();
    
    std::string showWindow = debugMode ? "SW_SHOW" : "SW_HIDE";
    std::string fMask = debugMode ? "SEE_MASK_NOCLOSEPROCESS" : "SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_NO_UI";
    
    std::string cppCode = R"(
#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <filesystem>
#include <ctime>
#include <thread>
#include <chrono>

namespace fs = std::filesystem;

enum ConsoleColor {
    BLACK = 0,
    BLUE = 1,
    GREEN = 2,
    CYAN = 3,
    RED = 4,
    MAGENTA = 5,
    YELLOW = 6,
    WHITE = 7,
    GRAY = 8,
    LIGHT_BLUE = 9,
    LIGHT_GREEN = 10,
    LIGHT_CYAN = 11,
    LIGHT_RED = 12,
    LIGHT_MAGENTA = 13,
    LIGHT_YELLOW = 14,
    BRIGHT_WHITE = 15
};

void setColor(int color) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, color);
}

bool deleteFileWithRetry(const std::string& filePath, int maxRetries = 5) {
    for (int i = 0; i < maxRetries; i++) {
        if (DeleteFileA(filePath.c_str())) {
            return true;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
    return false;
}

int main() {
    bool debugMode = )" + std::string(debugMode ? "true" : "false") + R"(;
    
    const char* scriptContent = ")" + escapedContent + R"(";
    
    char currentExe[MAX_PATH];
    GetModuleFileNameA(NULL, currentExe, MAX_PATH);
    std::string exePath = currentExe;
    fs::path exeDir = fs::path(exePath).parent_path();
    fs::path exeName = fs::path(exePath).filename();
    
    if (debugMode) {
        setColor(LIGHT_CYAN);
        std::cout << "\n";
        setColor(LIGHT_YELLOW);
        std::cout << "           Batch Wrapper Version 1.2\n";
        setColor(LIGHT_GREEN);
        std::cout << "           created by qaax_0\n";
        setColor(LIGHT_MAGENTA);
        std::cout << "           distributed by floppaware.neocities.org\n";
        setColor(WHITE);
        std::cout << "\n";
        setColor(LIGHT_YELLOW);
        std::cout << "  [DEBUG MODE] " << exeName.string() << "\n";
        setColor(LIGHT_CYAN);
        std::cout << "  [*] Working directory: " << exeDir.string() << "\n";
        setColor(WHITE);
    }
    
    srand(time(0));
    time_t now = time(0);
    std::string tempFile = (exeDir / ("temp_script_" + std::to_string(now) + "_" + std::to_string(rand()) + ".bat")).string();
    
    if (debugMode) {
        setColor(LIGHT_CYAN);
        std::cout << "  [*] Creating temporary file: " << tempFile << "\n";
        setColor(WHITE);
    }
    
    std::ofstream scriptFile(tempFile);
    if (!scriptFile.is_open()) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Could not create temporary file: " << tempFile << "\n";
        std::cerr << "  ERROR: " << strerror(errno) << "\n";
        setColor(WHITE);
        
        tempFile = "temp_script_" + std::to_string(now) + "_" + std::to_string(rand()) + ".bat";
        if (debugMode) {
            setColor(LIGHT_CYAN);
            std::cout << "  [*] Trying alternative location: " << tempFile << "\n";
            setColor(WHITE);
        }
        
        scriptFile.open(tempFile);
        if (!scriptFile.is_open()) {
            setColor(LIGHT_RED);
            std::cerr << "  ERROR: Could not create temporary file in current directory either!\n";
            setColor(WHITE);
            return 1;
        }
    }
    
    scriptFile << "@echo off" << std::endl;
    scriptFile << scriptContent;
    scriptFile.close();

    if (!fs::exists(tempFile)) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Temporary file was not created successfully\n";
        setColor(WHITE);
        return 1;
    }
    
    if (debugMode) {
        setColor(LIGHT_GREEN);
        std::cout << "  [+] Temporary file created successfully\n";
        setColor(LIGHT_CYAN);
        std::cout << "  [*] File size: " << fs::file_size(tempFile) << " bytes\n";
        setColor(WHITE);
    }
    
    SetFileAttributesA(tempFile.c_str(), FILE_ATTRIBUTE_HIDDEN);
    
    SHELLEXECUTEINFOA sei = {0};
    sei.cbSize = sizeof(SHELLEXECUTEINFOA);
    sei.fMask = )" + fMask + R"(;
    sei.hwnd = NULL;
    sei.lpVerb = "open";
    sei.lpFile = "cmd.exe";
    std::string cmdParams = "/c \"" + tempFile + "\"";
    sei.lpParameters = cmdParams.c_str();
    sei.lpDirectory = exeDir.string().c_str();
    sei.nShow = )" + showWindow + R"(;
    sei.hInstApp = NULL;
    
    if (debugMode) {
        setColor(LIGHT_CYAN);
        std::cout << "  [*] Executing: cmd.exe " << cmdParams << "\n";
        std::cout << "  [*] Working directory: " << exeDir.string() << "\n";
        setColor(WHITE);
    }
    
    if (!ShellExecuteExA(&sei)) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Could not execute script. Error: " << GetLastError() << "\n";
        setColor(WHITE);
        deleteFileWithRetry(tempFile);
        return 1;
    }
    
    if (sei.hProcess) {
        if (debugMode) {
            setColor(LIGHT_CYAN);
            std::cout << "  [*] Waiting for script to complete...\n";
            setColor(WHITE);
        }
        WaitForSingleObject(sei.hProcess, INFINITE);
        CloseHandle(sei.hProcess);
        
        if (debugMode) {
            setColor(LIGHT_GREEN);
            std::cout << "  [+] Script execution completed\n";
            setColor(WHITE);
        }
    }
    
    if (debugMode) {
        setColor(LIGHT_CYAN);
        std::cout << "  [*] Deleting temporary file...\n";
        setColor(WHITE);
    }
    
    if (deleteFileWithRetry(tempFile)) {
        if (debugMode) {
            setColor(LIGHT_GREEN);
            std::cout << "  [+] Temporary file deleted successfully\n";
            setColor(WHITE);
        }
    } else {
        setColor(LIGHT_YELLOW);
        std::cerr << "  WARNING: Could not delete temporary file after multiple retries\n";
        setColor(WHITE);

        std::string deleteCmd = "cmd.exe /c del /f /q \"" + tempFile + "\"";
        system(deleteCmd.c_str());
    }
    
    std::string originalScript = (exeDir / ")" + originalFilename + R"(").string();
    
    if (debugMode) {
        setColor(LIGHT_CYAN);
        std::cout << "  [*] Deleting original script: " << originalScript << "\n";
        setColor(WHITE);
    }
    
    if (deleteFileWithRetry(originalScript)) {
        if (debugMode) {
            setColor(LIGHT_GREEN);
            std::cout << "  [+] Original script deleted successfully\n";
            setColor(WHITE);
        }
    } else {
        setColor(LIGHT_YELLOW);
        std::cerr << "  WARNING: Could not delete original script: " << originalScript << "\n";
        setColor(WHITE);
    }
    
    if (debugMode) {
        setColor(LIGHT_CYAN);
        std::cout << "\n";
        setColor(LIGHT_GREEN);
        std::cout << "  Execution Complete!\n";
        setColor(WHITE);
        std::cout << "\n";
        std::cout << "  Press Enter to exit...";
        std::cin.get();
    }
    
    setColor(WHITE);
    return 0;
}
)";
    
    std::ofstream cppFile(outputPath);
    if (!cppFile.is_open()) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Could not create C++ file: " << outputPath << "\n";
        setColor(WHITE);
        return false;
    }
    cppFile << cppCode;
    cppFile.close();
    
    return true;
}

bool checkCompiler() {
    int result = system("g++ --version > nul 2>&1");
    if (result != 0) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: g++ compiler not found!\n";
        std::cerr << "  Please install MinGW or add it to PATH.\n";
        setColor(WHITE);
        return false;
    }
    return true;
}

std::string getInput(const std::string& prompt) {
    std::string input;
    setColor(LIGHT_YELLOW);
    std::cout << prompt;
    setColor(WHITE);
    std::getline(std::cin, input);
    return input;
}

int main(int argc, char* argv[]) {
    printBanner();
    
    bool debugMode = false;
    std::string scriptPath;
    
    if (argc == 1) {
        setColor(LIGHT_YELLOW);
        std::cout << "  No arguments provided.\n\n";
        setColor(WHITE);
        printUsage();
        
        std::string input = getInput("  Enter the path to your .bat or .cmd file: ");
        
        input.erase(0, input.find_first_not_of(" \t\n\r\f\v"));
        input.erase(input.find_last_not_of(" \t\n\r\f\v") + 1);
        
        if (input.empty()) {
            setColor(LIGHT_RED);
            std::cerr << "  ERROR: No file specified.\n";
            setColor(WHITE);
            return 1;
        }
        
        scriptPath = input;
        
        std::string debugInput = getInput("  Enable debug mode? (y/n): ");
        if (debugInput == "y" || debugInput == "Y" || debugInput == "yes" || debugInput == "YES") {
            debugMode = true;
        }
        
        std::cout << "\n";
    } else {
        for (int i = 1; i < argc; i++) {
            std::string arg = argv[i];
            
            if (arg == "debug" || arg == "d") {
                debugMode = true;
            } else if (arg.find(".bat") != std::string::npos || arg.find(".cmd") != std::string::npos) {
                scriptPath = arg;
            } else {
                setColor(LIGHT_YELLOW);
                std::cerr << "  WARNING: Unknown argument: " << arg << "\n";
                setColor(WHITE);
            }
        }
        
        if (scriptPath.empty()) {
            setColor(LIGHT_RED);
            std::cerr << "  ERROR: No script file specified.\n";
            setColor(WHITE);
            printUsage();
            return 1;
        }
    }
    
    if (!checkCompiler()) {
        return 1;
    }
    
    fs::path scriptFile(scriptPath);
    
    if (!fs::exists(scriptFile)) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: File not found: " << scriptPath << "\n";
        setColor(WHITE);
        return 1;
    }
    
    std::string extension = scriptFile.extension().string();
    if (extension != ".cmd" && extension != ".bat") {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: File must have .cmd or .bat extension\n";
        std::cerr << "  Got: " << extension << "\n";
        setColor(WHITE);
        return 1;
    }
    
    fs::path absolutePath = fs::absolute(scriptFile);
    fs::path scriptDir = absolutePath.parent_path();
    std::string baseName = getFileName(scriptPath);
    
    std::string cppFileName = baseName + ".cpp";
    std::string exeFileName = baseName + (debugMode ? "_debug.exe" : ".exe");
    fs::path cppPath = scriptDir / cppFileName;
    fs::path exePath = scriptDir / exeFileName;
    
    setColor(LIGHT_CYAN);
    std::cout << "  [.] Creating C++ Wrapper...\n";
    setColor(WHITE);
    std::cout << "\n";
    setColor(LIGHT_CYAN);
    std::cout << "  [*] Input file: " << scriptPath << "\n";
    std::cout << "  [*] Output file: " << exePath.string() << "\n";
    std::cout << "  [*] Debug mode: " << (debugMode ? "ON" : "OFF") << "\n";
    setColor(WHITE);
    std::cout << "\n";
    
    setColor(LIGHT_CYAN);
    std::cout << "  [*] Generating C++ source: " << cppPath.string() << "\n";
    setColor(WHITE);
    if (!writeCppWrapper(absolutePath.string(), cppPath.string(), debugMode)) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Failed to generate C++ wrapper\n";
        setColor(WHITE);
        return 1;
    }
    setColor(LIGHT_GREEN);
    std::cout << "  [+] C++ source generated successfully\n";
    setColor(WHITE);
    
    if (!compileWrapper(cppPath.string(), exePath.string())) {
        setColor(LIGHT_RED);
        std::cerr << "  ERROR: Compilation failed!\n";
        setColor(WHITE);
        return 1;
    }
    
    setColor(LIGHT_CYAN);
    std::cout << "  [*] Cleaning up temporary files...\n";
    setColor(WHITE);
    fs::remove(cppPath);
    setColor(LIGHT_GREEN);
    std::cout << "  [+] Cleanup complete\n";
    setColor(WHITE);
    
    std::cout << "\n";
    setColor(LIGHT_GREEN);
    std::cout << "  Wrapper Created!\n";
    setColor(WHITE);
    std::cout << "\n";
    setColor(LIGHT_YELLOW);
    std::cout << "  Executable: " << exePath.string() << "\n";
    setColor(WHITE);
    std::cout << "\n";
    std::cout << "  The wrapper will:\n";
    setColor(LIGHT_CYAN);
    std::cout << "    * Create a hidden temporary .bat file with your script\n";
    std::cout << "    * Execute it silently in the correct working directory\n";
    std::cout << "    * Delete the temporary file when done\n";
    std::cout << "    * Delete the original .bat/.cmd file on exit\n";
    setColor(WHITE);
    
    if (debugMode) {
        std::cout << "\n";
        setColor(LIGHT_YELLOW);
        std::cout << "  [DEBUG VERSION] Will show console window with status messages\n";
        std::cout << "  Run with: " << exeFileName << "\n";
        setColor(WHITE);
    } else {
        std::cout << "\n";
        setColor(LIGHT_GREEN);
        std::cout << "  To use it, just run: " << exeFileName << "\n";
        setColor(LIGHT_CYAN);
        std::cout << "  For debug version: " << baseName << "_debug.exe\n";
        setColor(WHITE);
    }
    
    std::cout << "\n";
    
    return 0;
}