#include "SendSuperTokenToPlatform.h"


#include <windows.h>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")

#include <string>
#include <vector>
#include <codecvt>
#include <locale>
#include <iostream>

// Example RTB token template (converted from C# verbatim string).
// Contains placeholders {0}, {1}, {2}, {3} intended for formatting/replace later.
const std::string k_rtbTokenForGettingAdmMax = R"(
{
  "id": "123456",
  "imp": [
    {
      "id": "234567",
      "video": {
        "mimes": [
          "video/mp4"
        ],
        "minduration": 0,
        "maxduration": 1234,
        "protocols": [
          2,
          5
        ],
        "w": 1536,
        "h": 2048,
        "linearity": 1,
        "minbitrate": 250,
        "maxbitrate": 9999,
        "boxingallowed": 1,
        "playbackmethod": [
          1,
          2,
          3,
          4
        ],
        "delivery": [
          2
        ],
        "pos": 7
      },
      "displaymanager": "Vungle",
      "displaymanagerver": "5.0.0",
      "tagid": "{1}",
      "bidfloor": 2,
      "bidfloorcur": "USD",
      "secure": 1,
      "ext": {
        "vungle": {
          "bid_token": "{2}"
        }
      }
    }
  ],
  "app": {
    "id": "{0}",
    "name": "Tiles-Template-Test-App",
    "storeurl": "http://www.vungle.com",
    "privacypolicy": 1,
    "publisher": {
        "id": "345678"
    }
  },
  "device": {
    "ip": "{3}",
    "w": 640,
    "os": "windows",
    "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
    "h": 1136,
    "osv": "14",
    "connectiontype": 2,
    "ifa": "4423DD36-2738-46DC-84D1-02A47F95320D1",
    "language": "en",
    "pxratio": 2,
    "dnt": 0,
    "js": 1,
    "ext": { }
  },
  "at": 2,
  "tmax": 5000,
  "cur": [
    "USD"
  ],
  "user":{ },
  "test": 1,
  "regs": {
    "coppa": 1
  }
}
)";


// Synchronous HTTP POST using WinHTTP that mirrors the C# GetPlatformAdmResponse behavior.
// Returns response body on success, empty string on failure.
// Added `useProxy` parameter: when true, this will route requests through 127.0.0.1:8888.
static std::string GetPlatformAdmResponse(const std::string& url, const std::string& data, bool useProxy)
{
    if (url.empty()) return std::string();

    // Convert URL to wide
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring wurl = converter.from_bytes(url);

    // Simple URL parsing to extract scheme, host, port and path
    std::wstring scheme;
    std::wstring host;
    std::wstring path = L"/";
    INTERNET_PORT port = INTERNET_DEFAULT_HTTP_PORT;
    bool isHttps = false;

    size_t schemePos = wurl.find(L"://");
    size_t hostStart = 0;
    if (schemePos != std::wstring::npos) {
        scheme = wurl.substr(0, schemePos);
        hostStart = schemePos + 3;
        if (_wcsicmp(scheme.c_str(), L"https") == 0) {
            isHttps = true;
            port = INTERNET_DEFAULT_HTTPS_PORT;
        }
    }

    size_t pathPos = wurl.find(L'/', hostStart);
    if (pathPos != std::wstring::npos) {
        host = wurl.substr(hostStart, pathPos - hostStart);
        path = wurl.substr(pathPos);
    }
    else {
        host = wurl.substr(hostStart);
        path = L"/";
    }

    // check for explicit port in host
    size_t colonPos = host.find(L':');
    if (colonPos != std::wstring::npos) {
        std::wstring portStr = host.substr(colonPos + 1);
        host = host.substr(0, colonPos);
        try {
            int p = std::stoi(std::string(converter.to_bytes(portStr)));
            if (p > 0) port = static_cast<INTERNET_PORT>(p);
        }
        catch (...) { /* ignore and use default */ }
    }

    HINTERNET hSession = nullptr;
    HINTERNET hConnect = nullptr;
    HINTERNET hRequest = nullptr;
    std::string responseBody;

    // Prepare headers
    std::string headers =
        "user-agent: Vungle/7.0.0\r\n"
        "x-vungle-timezone: Asia/Shanghai\r\n"
        "x-vungle-language: en-us\r\n"
        "x-vungle-bundle-id: com.outfit7.mytalkingtomfree\r\n"
        "Vungle-explain: jaeger\r\n"
        "Vungle-Version: 5.8\r\n"
        "Content-Type: application/json\r\n";

    // Convert host and path to wide
    std::wstring whost = host;
    std::wstring wpath = path;

    // If useProxy is true, point WinHttpOpen to the local proxy.
    LPCWSTR proxyName = WINHTTP_NO_PROXY_NAME;
    DWORD accessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
    if (useProxy) {
        accessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
        // WinHTTP accepts proxy in the form "http://127.0.0.1:8888" or "127.0.0.1:8888"
        // Use the numeric address and port.
        // Note: If your proxy expects the scheme, include "http://".
        static const wchar_t localProxy[] = L"127.0.0.1:8888";
        proxyName = localProxy;
    }

    do {
        hSession = WinHttpOpen(L"Vungle/7.0.0",
            accessType,
            proxyName,
            WINHTTP_NO_PROXY_BYPASS,
            0);
        if (!hSession) break;

        hConnect = WinHttpConnect(hSession, whost.c_str(), port, 0);
        if (!hConnect) break;

        DWORD flags = isHttps ? WINHTTP_FLAG_SECURE : 0;
        hRequest = WinHttpOpenRequest(hConnect,
            L"POST",
            wpath.c_str(),
            NULL,
            WINHTTP_NO_REFERER,
            WINHTTP_DEFAULT_ACCEPT_TYPES,
            flags);
        if (!hRequest) break;

        // Add headers
        std::wstring wheaders = converter.from_bytes(headers);
        if (!WinHttpAddRequestHeaders(hRequest, wheaders.c_str(), (DWORD)-1L, WINHTTP_ADDREQ_FLAG_ADD)) {
            // proceed anyway; not fatal
        }

        // Send request with data (UTF-8)
        BOOL sendOk = WinHttpSendRequest(hRequest,
            WINHTTP_NO_ADDITIONAL_HEADERS,
            0,
            (LPVOID)data.data(),
            static_cast<DWORD>(data.size()),
            static_cast<DWORD>(data.size()),
            0);
        if (!sendOk) break;

        if (!WinHttpReceiveResponse(hRequest, NULL)) break;

        // Read response
        DWORD dwSize = 0;
        do {
            if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) break;
            if (dwSize == 0) break;

            std::vector<char> buffer(dwSize);
            DWORD dwRead = 0;
            if (!WinHttpReadData(hRequest, buffer.data(), dwSize, &dwRead)) break;
            if (dwRead == 0) break;

            responseBody.append(buffer.data(), dwRead);
        } while (dwSize > 0);
    } while (false);

    if (hRequest) WinHttpCloseHandle(hRequest);
    if (hConnect) WinHttpCloseHandle(hConnect);
    if (hSession) WinHttpCloseHandle(hSession);

    return responseBody; // empty on error
}

// Now builds the RTB request by replacing placeholders and returns platform response.
std::string GetAdmFromRtbToken(
    const std::string& appId,
    const std::string& placement,
    const std::string& ip,
    const std::string& token,
    const std::string& endpoint)
{
    // Build request from template by replacing placeholders {0},{1},{2},{3}.
    std::string request = k_rtbTokenForGettingAdmMax;

    auto replaceAll = [](std::string& s, const std::string& from, const std::string& to) {
        if (from.empty()) return;
        size_t start = 0;
        while ((start = s.find(from, start)) != std::string::npos) {
            s.replace(start, from.length(), to);
            start += to.length();
        }
    };

    replaceAll(request, "{0}", appId);
    replaceAll(request, "{1}", placement);
    replaceAll(request, "{2}", token);
    replaceAll(request, "{3}", ip);

    // Call platform endpoint with built request and return its response.
    // Pass `useProxy` as false by default. Set to true for local proxy debugging.
    bool useProxy = false;
    std::string platformResponse = GetPlatformAdmResponse(endpoint, request, useProxy);
    return platformResponse;
}

