#include "MixpanelScript.h"
#define _WIN32_DCOM
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

void MixpanelScript::PostData(std::string EventName, std::string DistinctId, std::string InsertId, int error)
{
    CURL* curl;
    CURLcode res;

    time_t systemtime;
    time(&systemtime);
    nlohmann::json data = { {{"event", EventName},
                  {"properties",
                   {{"time", systemtime},
                    {"distinct_id", DistinctId},
                    {"error", error},
                    {"$insert_id",
                    InsertId}}}} };
    std::string data_str = data.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
    curl_global_init(CURL_GLOBAL_ALL);

    curl = curl_easy_init();
    if (curl) {

        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
        // 设置请求URL和参数
        curl_easy_setopt(curl, CURLOPT_URL,
            "https://api.mixpanel.com/import?strict=1");

        // 设置身份验证(填API_Secret)
        curl_easy_setopt(curl, CURLOPT_USERPWD, "b1074a764fc7926acbc978d13ad663d7");

        // 设置请求头
        struct curl_slist* headers = NULL;
        headers = curl_slist_append(headers, "accept: application/json");
        headers = curl_slist_append(headers, "Content-Type: application/json");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);


        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data_str.c_str());

        // 发送请求
        res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));
        }

        // 回收资源
        curl_easy_cleanup(curl);
        curl_slist_free_all(headers);
    }

    curl_global_cleanup();
}

std::string MixpanelScript::GetGUID()
{
    std::string guidString="";
    GUID uuid; // 用于存储GUID的变量

    // 生成GUID
    if (UuidCreate(&uuid) != RPC_S_OK) {
        std::cerr << "Error generating GUID" << std::endl;
        return guidString;
    }

    // 将GUID转换为自字符串
    RPC_CSTR szUuid = NULL;
    if (UuidToStringA(&uuid, &szUuid) != RPC_S_OK) {
        std::cerr << "Error converting GUID to string" << std::endl;
        return guidString;
    }

    // 释放内存
    RpcStringFreeA(&szUuid);
    guidString = GuidToString(uuid);
    return guidString;
}

std::string MixpanelScript::GetCPUID()
{
    std::string wmi = "XXXXXXXXXXXXXXXX";
    HRESULT hres;

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        return "XXXXXXXXXXXXXXXX";                   
    }


    hres = CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities 
        NULL                         // Reserved
    );


    if (FAILED(hres))
    {
        CoUninitialize();
        return "XXXXXXXXXXXXXXXX";                  
    }

    IWbemLocator* pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID*)&pLoc);

    if (FAILED(hres))
    {
        CoUninitialize();
        return "XXXXXXXXXXXXXXXX";                    // Program has failed.
    }
    IWbemServices* pSvc = NULL;

    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
        NULL,                    // User name. NULL = current user
        NULL,                    // User password. NULL = current
        0,                       // Locale. NULL indicates current
        NULL,                    // Security flags.
        0,                       // Authority (for example, Kerberos)
        0,                       // Context object 
        &pSvc                    // pointer to IWbemServices proxy
    );

    if (FAILED(hres))
    {
        pLoc->Release();
        CoUninitialize();
        return "XXXXXXXXXXXXXXXX";        // Program has failed.
    }

    hres = CoSetProxyBlanket(
        pSvc,                        // Indicates the proxy to set
        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
        NULL,                        // Server principal name 
        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
        NULL,                        // client identity
        EOAC_NONE                    // proxy capabilities 
    );

    if (FAILED(hres))
    {
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return "XXXXXXXXXXXXXXXX";               // Program has failed.
    }

    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"),
        bstr_t("SELECT * FROM Win32_Processor"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator);

    if (FAILED(hres))
    {
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return "XXXXXXXXXXXXXXXX";              // Program has failed.
    }

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
            &pclsObj, &uReturn);

        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        VariantInit(&vtProp);
        // Get the value of the Name property
        hr = pclsObj->Get(L"ProcessorId", 0, &vtProp, 0, 0);
        _bstr_t bstr_t(vtProp.bstrVal);
        wmi= bstr_t;
        VariantClear(&vtProp);

        pclsObj->Release();
    }
    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();
    return wmi;
}

std::string MixpanelScript::GuidToString(const GUID& guid)
{
    std::ostringstream oss;
    oss << std::hex << std::setw(8) << std::setfill('0') << guid.Data1
        << std::setw(4) << std::setfill('0') << guid.Data2
        << std::setw(4) << std::setfill('0') << guid.Data3
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[0])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[1])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[2])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[3])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[4])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[5])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[6])
        << std::setw(2) << std::setfill('0') << static_cast<int>(guid.Data4[7]);

    return oss.str();
}
