#include <iostream>
#include <fstream>
#include <string>
#include <curl/curl.h>
#include <thread>
#include <chrono>
#include <windows.h>
#include "nlohmann/json.hpp"  // Ensure this points correctly to the json.hpp file from nlohmann/json

// Make sure you are using the nlohmann json namespace
using json = nlohmann::json;

// Curl write callback
std::size_t writeCallback(void* contents, std::size_t size, std::size_t nmemb, std::string* s) {
    size_t newLength = size * nmemb;
    try {
        s->append((char*)contents, newLength);
    }
    catch (std::bad_alloc& e) {
        // Handle memory bad_alloc error
        return 0;
    }
    return newLength;
}

// Function to perform HTTP GET request
bool performRequest(const std::string& url, const std::string& savePath) {
    CURL* curl = curl_easy_init();
    if (!curl) {
        std::cerr << "Curl initialization failed!" << std::endl;
        return false;
    }

    CURLcode res;
    std::string response_string;

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);

    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        curl_easy_cleanup(curl);
        return false;
    }

    std::ofstream outFile(savePath);
    if (!outFile.is_open()) {
        std::cerr << "Failed to open " << savePath << std::endl;
        curl_easy_cleanup(curl);
        return false;
    }

    outFile << response_string;
    outFile.close();

    curl_easy_cleanup(curl);
    return true;
}

// Function to load JSON configuration
json loadConfig(const std::string& configPath) {
    std::ifstream configFile(configPath);
    json configJson;
    if (configFile.is_open()) {
        configFile >> configJson;
    }
    else {
        std::cerr << "Unable to open config file" << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return configJson;
}

// Function to launch and wait for an external process
void launchAndWait(const std::string& executablePath) {
    STARTUPINFOA si; // Specific use of STARTUPINFOA for ANSI characters.
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi;

    if (!CreateProcessA(NULL, const_cast<char*>(executablePath.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        std::cerr << "Failed to start process. Error: " << GetLastError() << std::endl;
        std::exit(EXIT_FAILURE);
    }

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " < config file path > \n";
        return 1;
    }

    auto config = loadConfig(argv[1]);
    std::string url = config["url"];
    std::string jsonPath = config["jsonPath"];
    int interval = config["interval"];
    std::string launchPath = config["launchPath"];

    std::thread otherApp(launchAndWait, launchPath);

    while (otherApp.joinable()) {
        if (!performRequest(url, jsonPath)) {
            std::cerr << "Error performing HTTP request." << std::endl;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(interval));
    }

    otherApp.join();
    return 0;
}

Remove args and use specific config with specific name