#pragma once

#include "lite_wallet_gateway.h"  // LiteWalletRefreshBundle / LiteWalletRefreshResult

#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>

namespace dragonx::wallet {

enum class LiteWalletAppAddressKind {
    Shielded,
    Transparent,
};

enum class LiteWalletAppTransactionKind {
    Unknown,
    Send,
    Receive,
};

enum class LiteWalletStateMapIssue {
    EmptyBundle,
    IncompleteBundle,
};

struct LiteWalletAppChainModel {
    std::optional<std::string> chainName;
    std::optional<std::string> version;
    std::optional<std::string> vendor;
    std::optional<std::int64_t> latestBlockHeight;
    std::optional<std::int64_t> difficulty;
    std::optional<std::int64_t> longestChain;
    std::optional<std::int64_t> notarized;
};

struct LiteWalletAppHeightModel {
    std::int64_t height = 0;
};

struct LiteWalletAppBalanceModel {
    std::uint64_t transparentZatoshis = 0;
    std::uint64_t shieldedZatoshis = 0;
    std::uint64_t unconfirmedZatoshis = 0;
    std::uint64_t verifiedShieldedZatoshis = 0;
    std::uint64_t spendableShieldedZatoshis = 0;
    std::uint64_t totalZatoshis = 0;
};

struct LiteWalletAppAddressModel {
    std::string address;
    LiteWalletAppAddressKind kind = LiteWalletAppAddressKind::Shielded;
    bool spendabilityKnown = false;
    bool spendable = false;
};

struct LiteWalletAppSpendableOutputModel {
    LiteSpendableOutputKind kind = LiteSpendableOutputKind::UnspentNote;
    std::string address;
    std::string createdInTxid;
    std::optional<std::int64_t> createdInBlock;
    std::uint64_t valueZatoshis = 0;
    bool spent = false;
    bool unconfirmedSpent = false;
    bool pending = false;
    bool spendable = false;
};

struct LiteWalletAppTransactionOutputModel {
    std::string address;
    std::int64_t valueZatoshis = 0;
    std::string memo;
};

struct LiteWalletAppTransactionModel {
    std::string txid;
    LiteWalletAppTransactionKind kind = LiteWalletAppTransactionKind::Unknown;
    std::int64_t timestamp = 0;
    std::optional<std::int64_t> blockHeight;
    bool unconfirmed = false;
    std::string address;
    std::int64_t amountZatoshis = 0;
    std::int64_t signedAmountZatoshis = 0;
    std::string memo;
    std::optional<std::int64_t> position;
    std::vector<LiteWalletAppTransactionOutputModel> outgoingOutputs;
};

struct LiteWalletAppSyncModel {
    std::uint64_t walletHeight = 0;
    std::uint64_t chainHeight = 0;
    double progress = 0.0;
    bool complete = false;
};

struct LiteWalletAppRefreshModel {
    bool complete = false;
    bool hasChainInfo = false;
    bool hasHeight = false;
    bool hasBalance = false;
    bool hasAddresses = false;
    bool hasSpendableOutputs = false;
    bool hasTransactions = false;
    bool hasSyncStatus = false;
    bool hasEncryptionStatus = false;
    bool encrypted = false;
    bool locked = false;
    std::size_t successfulCommandCount = 0;

    LiteWalletAppChainModel chain;
    LiteWalletAppHeightModel height;
    LiteWalletAppBalanceModel balance;
    LiteWalletAppSyncModel sync;
    std::vector<LiteWalletAppAddressModel> addresses;
    std::vector<LiteWalletAppSpendableOutputModel> spendableOutputs;
    std::vector<LiteWalletAppTransactionModel> transactions;
};

struct LiteWalletStateMapIssueInfo {
    LiteWalletStateMapIssue issue = LiteWalletStateMapIssue::EmptyBundle;
    std::string message;
};

struct LiteWalletStateMapResult {
    bool ok = false;
    bool stateMutationAllowed = false;
    LiteWalletAppRefreshModel model;
    std::vector<LiteWalletStateMapIssueInfo> issues;
    std::string error;
};

const char* liteWalletAppAddressKindName(LiteWalletAppAddressKind kind);
const char* liteWalletAppTransactionKindName(LiteWalletAppTransactionKind kind);
const char* liteWalletStateMapIssueName(LiteWalletStateMapIssue issue);

LiteWalletStateMapResult mapLiteWalletRefreshBundle(const LiteWalletRefreshBundle& bundle);
LiteWalletStateMapResult mapLiteWalletRefreshResult(const LiteWalletRefreshResult& result);

} // namespace dragonx::wallet