// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
//
// Real-backend smoke harness for the lite wallet bridge. Links the actual SDXL litelib_*
// backend (via the same imported CMake target the app uses) and exercises LiteClientBridge
// against a real lightwalletd server. The "real backend smoke test" the plan gates behind
// passing fake-backend tests.
//
//   lite_smoke [server-url] [--create] [--refresh] [--full] [--restore-recent]
//
// Read-only by default. --create initializes a new wallet. --refresh runs the refresh
// commands through the parsers (shape check). --full also does a (slow) full sync first.
// --restore-recent restores a throwaway wallet with a birthday near the tip so the sync is
// minimal (seconds), then runs the data-shape checks — fast verification of balance/addresses/
// list shapes without a multi-minute full scan. Always run with an isolated HOME.

#include "wallet/lite_client_bridge.h"
#include "wallet/lite_connection_service.h"
#include "wallet/lite_result_parsers.h"

#include <cstdio>
#include <string>

using namespace dragonx::wallet;

// A standard valid 24-word BIP39 test mnemonic (no funds). Restored only into an isolated HOME.
static const char* kTestSeed =
    "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon "
    "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon "
    "abandon art";

// Push each refresh command's real output through its parser; print flags/counts, and the raw
// (truncated) response only on a parse failure to diagnose real-shape mismatches.
static void runDataShapeChecks(LiteClientBridge& bridge)
{
    // Non-blocking commands first (read local wallet state); balance last (may need a sync).
    {
        auto r = bridge.execute("syncstatus", "");
        auto p = parseLiteSyncStatusResponse(r.value);
        std::printf("[lite-smoke] syncstatus parse_ok=%d complete=%d synced=%llu/%llu\n",
                    p.ok, p.syncStatus.complete,
                    (unsigned long long)p.syncStatus.syncedBlocks, (unsigned long long)p.syncStatus.totalBlocks);
        if (!p.ok) std::printf("[lite-smoke]   syncstatus RAW = %.150s\n", r.value.c_str());
    }
    {
        auto r = bridge.execute("addresses", "");
        auto p = parseLiteAddressesResponse(r.value);
        std::printf("[lite-smoke] addresses  bridge_ok=%d parse_ok=%d err=%s z=%zu t=%zu\n",
                    r.ok, p.ok, liteResultParserErrorName(p.error),
                    p.addresses.zAddresses.size(), p.addresses.tAddresses.size());
        if (!p.ok) std::printf("[lite-smoke]   addresses RAW = %.150s\n", r.value.c_str());
    }
    {
        auto r = bridge.execute("list", "");
        auto p = parseLiteTransactionsResponse(r.value);
        std::printf("[lite-smoke] list       bridge_ok=%d parse_ok=%d err=%s count=%zu\n",
                    r.ok, p.ok, liteResultParserErrorName(p.error), p.transactions.transactions.size());
        if (!p.ok) std::printf("[lite-smoke]   list RAW = %.150s\n", r.value.c_str());
    }
    std::printf("[lite-smoke] balance (may block until synced)...\n");
    {
        auto r = bridge.execute("balance", "");
        auto p = parseLiteBalanceResponse(r.value);
        std::printf("[lite-smoke] balance    bridge_ok=%d parse_ok=%d err=%s\n",
                    r.ok, p.ok, liteResultParserErrorName(p.error));
        if (!p.ok) std::printf("[lite-smoke]   balance RAW = %.150s\n", r.value.c_str());
    }
}

int main(int argc, char** argv)
{
    std::setvbuf(stdout, nullptr, _IONBF, 0);  // unbuffered so output survives a timeout kill

    std::string server = "https://lite.dragonx.is";
    bool doCreate = false, doRefresh = false, doFull = false, doRestoreRecent = false;
    for (int i = 1; i < argc; ++i) {
        const std::string arg = argv[i];
        if (arg == "--create") doCreate = true;
        else if (arg == "--refresh") doRefresh = true;
        else if (arg == "--full") doFull = true;
        else if (arg == "--restore-recent") doRestoreRecent = true;
        else server = arg;
    }

    std::printf("[lite-smoke] server      = %s\n", server.c_str());

    auto bridge = LiteClientBridge::linkedSdxl();
    std::printf("[lite-smoke] available() = %s\n", bridge.available() ? "true" : "false");
    if (!bridge.available()) {
        std::printf("[lite-smoke] reason      = %s\n", bridge.unavailableReason().c_str());
        std::printf("[lite-smoke] FAIL: backend not linked\n");
        return 2;
    }

    std::printf("[lite-smoke] walletExists(%s) = %s\n", kDragonXLiteChainName,
                bridge.walletExists(kDragonXLiteChainName) ? "true" : "false");
    std::printf("[lite-smoke] checkServerOnline()   = %s\n", bridge.checkServerOnline(server) ? "true" : "false");

    if (doRestoreRecent) {
        // Bootstrap a client to learn the chain tip, then restore a throwaway wallet with a
        // birthday near the tip so the scan is minimal (seconds), then check data shapes.
        std::printf("[lite-smoke] bootstrap initializeNew() to learn tip...\n");
        bridge.initializeNew(false, server);
        unsigned long long tip = 0;
        {
            auto r = bridge.execute("info", "");
            auto p = parseLiteInfoResponse(r.value);
            tip = p.info.latestBlockHeight.has_value() ? (unsigned long long)*p.info.latestBlockHeight : 0;
            std::printf("[lite-smoke] info parse_ok=%d tip=%llu\n", p.ok, tip);
        }
        const unsigned long long birthday = tip > 10 ? tip - 10 : tip;
        std::printf("[lite-smoke] restore-from-phrase at birthday=%llu (minimal scan)...\n", birthday);
        auto rr = bridge.initializeNewFromPhrase(false, server, kTestSeed, birthday, 0, /*overwrite*/ true);
        std::printf("[lite-smoke] restore ok=%d\n", rr.ok);
        if (!rr.ok) std::printf("[lite-smoke]   restore err = %s\n", rr.error.c_str());
        // NB: this backend downloads from a fixed checkpoint regardless of birthday, so an
        // explicit full "sync" is slow. addresses/list/syncstatus read local state and don't
        // need it; balance may block until synced.
        std::printf("[lite-smoke] --- data shape check (no full sync) ---\n");
        runDataShapeChecks(bridge);
        bridge.shutdown();
        std::printf("[lite-smoke] done\n");
        return 0;
    }

    if (doCreate) {
        std::printf("[lite-smoke] initializeNew() ... (real network + writes wallet state)\n");
        auto result = bridge.initializeNew(false, server);
        std::printf("[lite-smoke] initializeNew ok = %s\n", result.ok ? "true" : "false");
        if (result.ok) {
            std::printf("[lite-smoke]   wallet created; response len = %zu (seed redacted)\n", result.value.size());
        } else {
            std::printf("[lite-smoke]   error = %s\n", result.error.c_str());
        }
    }

    if (doRefresh) {
        std::printf("[lite-smoke] --- refresh shape check (real backend output -> parsers) ---\n");
        {
            auto r = bridge.execute("info", "");
            auto p = parseLiteInfoResponse(r.value);
            std::printf("[lite-smoke] info       bridge_ok=%d parse_ok=%d err=%s\n",
                        r.ok, p.ok, liteResultParserErrorName(p.error));
        }
        if (!doFull) {
            bridge.shutdown();
            std::printf("[lite-smoke] (skipping balance/addresses/list; pass --full or --restore-recent)\n");
            return 0;
        }
        std::printf("[lite-smoke] running full sync (blocking; can take many minutes)...\n");
        bridge.execute("sync", "");
        runDataShapeChecks(bridge);
    }

    bridge.shutdown();
    std::printf("[lite-smoke] done\n");
    return 0;
}
