// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#include "lite_server_probe.h"

#include "logger.h"

#include <curl/curl.h>

#include <utility>

namespace dragonx {
namespace util {

std::string liteServerHost(const std::string& url)
{
    // Strip scheme ("scheme://") then take everything up to the first '/', '?' or '#'.
    std::string s = url;
    const auto scheme = s.find("://");
    if (scheme != std::string::npos) s = s.substr(scheme + 3);
    const auto end = s.find_first_of("/?#");
    if (end != std::string::npos) s = s.substr(0, end);
    // Drop any userinfo ("user@host").
    const auto at = s.find('@');
    if (at != std::string::npos) s = s.substr(at + 1);
    return s;
}

LiteServerProbe::~LiteServerProbe()
{
    cancel_ = true;
    if (worker_.joinable()) worker_.join();
}

void LiteServerProbe::start(std::vector<std::string> urls)
{
    // Replace any in-flight probe.
    cancel_ = true;
    if (worker_.joinable()) worker_.join();
    cancel_ = false;
    busy_ = true;
    worker_ = std::thread([this, urls = std::move(urls)]() mutable { run(std::move(urls)); });
}

std::map<std::string, LiteServerProbeResult> LiteServerProbe::results() const
{
    std::lock_guard<std::mutex> lk(mutex_);
    return results_;
}

void LiteServerProbe::run(std::vector<std::string> urls)
{
    for (const auto& url : urls) {
        if (cancel_.load()) break;

        LiteServerProbeResult r;
        r.probed = true;

        CURL* c = curl_easy_init();
        if (c) {
            curl_easy_setopt(c, CURLOPT_URL, url.c_str());
            curl_easy_setopt(c, CURLOPT_CONNECT_ONLY, 1L);     // TCP+TLS handshake only
            curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, 5L);
            curl_easy_setopt(c, CURLOPT_TIMEOUT, 8L);
            curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L);         // thread-safe resolver
            curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 0L);
            curl_easy_setopt(c, CURLOPT_USERAGENT, "ObsidianDragon/1.0");
            curl_easy_setopt(c, CURLOPT_SSL_VERIFYPEER, 1L);
            curl_easy_setopt(c, CURLOPT_SSL_VERIFYHOST, 2L);

            const CURLcode res = curl_easy_perform(c);
            if (res == CURLE_OK) {
                r.online = true;
                double t = 0.0;
                // Prefer TLS-handshake-complete time; fall back to TCP connect time.
                if (curl_easy_getinfo(c, CURLINFO_APPCONNECT_TIME, &t) != CURLE_OK || t <= 0.0)
                    curl_easy_getinfo(c, CURLINFO_CONNECT_TIME, &t);
                r.latencyMs = t > 0.0 ? static_cast<int>(t * 1000.0) : 0;
                char* ip = nullptr;
                if (curl_easy_getinfo(c, CURLINFO_PRIMARY_IP, &ip) == CURLE_OK && ip)
                    r.ip = ip;
            } else {
                DEBUG_LOGF("[lite-probe] %s: %s\n", url.c_str(), curl_easy_strerror(res));
            }
            curl_easy_cleanup(c);
        }

        std::lock_guard<std::mutex> lk(mutex_);
        results_[url] = r;
    }
    busy_ = false;
}

} // namespace util
} // namespace dragonx
