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

#include "lite_owned_string.h"

#include <algorithm>
#include <utility>

namespace dragonx {
namespace wallet {

namespace {
// A backend response is a failure when it is prefixed with "Error:" (the litelib_* convention).
bool looksLikeError(const std::string& value)
{
    return value.rfind("Error:", 0) == 0;
}

// Best-effort scrub of a copied secret-ish payload before the string is released.
void wipeString(std::string& value)
{
    std::fill(value.begin(), value.end(), '\0');
    value.clear();
}
}  // namespace

LiteBridgeOwnedString::LiteBridgeOwnedString(char* rawValue, FreeStringFn freeString)
    : rawValue_(rawValue),
      freeString_(freeString),
      rawPointerReceived_(rawValue != nullptr)
{
}

LiteBridgeOwnedString::LiteBridgeOwnedString(LiteBridgeOwnedString&& other) noexcept
{
    moveFrom(std::move(other));
}

LiteBridgeOwnedString& LiteBridgeOwnedString::operator=(LiteBridgeOwnedString&& other) noexcept
{
    if (this == &other) return *this;
    copyValueBeforeFree();
    releaseRawValue();
    wipeString(copiedValue_);
    moveFrom(std::move(other));
    return *this;
}

LiteBridgeOwnedString::~LiteBridgeOwnedString()
{
    copyValueBeforeFree();
    releaseRawValue();
    wipeString(copiedValue_);
}

LiteBridgeStringResult LiteBridgeOwnedString::intoResult()
{
    if (resultTaken_) return {false, {}, "lite bridge string result already consumed"};
    resultTaken_ = true;

    if (!rawPointerReceived_) return {false, {}, "lite bridge returned a null string"};
    if (!rawValue_) return {false, {}, "lite bridge string was already released"};
    if (!freeString_) {
        rawValue_ = nullptr;
        return {false, {}, "lite bridge freeString function is unavailable"};
    }

    copyValueBeforeFree();
    releaseRawValue();

    const std::string resultValue = copiedValue_;
    wipeString(copiedValue_);
    if (looksLikeError(resultValue)) return {false, {}, resultValue};
    return {true, resultValue, {}};
}

void LiteBridgeOwnedString::copyValueBeforeFree()
{
    if (!rawValue_ || copiedBeforeFree_) return;
    copiedValue_ = rawValue_;
    copiedBeforeFree_ = true;
}

void LiteBridgeOwnedString::releaseRawValue()
{
    if (!rawValue_) return;
    if (freeString_) {
        freeString_(rawValue_);
        freed_ = true;
    }
    rawValue_ = nullptr;
}

void LiteBridgeOwnedString::moveFrom(LiteBridgeOwnedString&& other) noexcept
{
    rawValue_ = other.rawValue_;
    freeString_ = other.freeString_;
    rawPointerReceived_ = other.rawPointerReceived_;
    copiedBeforeFree_ = other.copiedBeforeFree_;
    freed_ = other.freed_;
    resultTaken_ = other.resultTaken_;
    copiedValue_ = std::move(other.copiedValue_);

    other.rawValue_ = nullptr;
    other.freeString_ = nullptr;
    other.rawPointerReceived_ = false;
    other.copiedBeforeFree_ = false;
    other.freed_ = false;
    other.resultTaken_ = true;
    wipeString(other.copiedValue_);
}

LiteBridgeStringResult liteBridgeRuntimeTakeOwnedString(
    char* rawValue,
    LiteClientBridgeApi::FreeStringFn freeString)
{
    LiteBridgeOwnedString ownedString(rawValue, freeString);
    return ownedString.intoResult();
}

}  // namespace wallet
}  // namespace dragonx
