// Copyright (c) 2016-2024 The Hush developers
// Copyright (c) 2024-2026 The DragonX developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
#ifndef ASYNCRPCOPERATION_AUTOSHIELDCOINBASE_H
#define ASYNCRPCOPERATION_AUTOSHIELDCOINBASE_H

#include "amount.h"
#include "asyncrpcoperation.h"
#include "univalue.h"
#include "zcash/Address.hpp"
#include "zcash/zip32.h"

// Sentinel for "not a derived account" (i.e. the configured -autoshieldaddress).
static const uint32_t AUTOSHIELD_ACCOUNT_NONE = UINT32_MAX;

enum class AutoShieldDestStatus {
    Resolved,        // destOut/destStrOut are set
    NotFound,        // no in-gap account held yet; the operation will derive one
    InvalidOverride, // -autoshieldaddress is set but is not a Sapling address
    NoSeed,          // no HD seed available (e.g. locked wallet)
};

// Resolve the auto-shield destination WITHOUT mutating the wallet: the configured
// -autoshieldaddress if set, else the lowest in-gap seed-derived account the wallet
// already holds. It deliberately does NOT generate a key, so init can call it purely
// to answer "where will this send?" -- deriving a fresh account as a side effect of
// populating a status field would be wrong. The operation's own resolveDestination
// falls through to generation when this returns NotFound.
// Caller must hold cs_wallet.
AutoShieldDestStatus ResolveAutoShieldDestinationReadOnly(
    libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut, uint32_t& accountOut);

// A periodic, wallet-local operation that drains matured *transparent* coinbase
// UTXOs into a wallet-owned Sapling z-address in size-bounded batches. It is the
// automatic sibling of the manual z_shieldcoinbase RPC and mirrors the dispatch
// model of AsyncRPCOperation_sweep (self-gathers on the async worker thread,
// commits via CWallet::CommitAutomatedTx). It never mints a transparent output,
// so it respects the ac_private=1 transparent-output ban, and it deliberately
// does NOT toggle mining (unlike z_shieldcoinbase) so it can run every interval
// on a mining node without thrashing the miner.
class AsyncRPCOperation_autoshieldcoinbase : public AsyncRPCOperation
{
public:
    AsyncRPCOperation_autoshieldcoinbase(int targetHeight);
    virtual ~AsyncRPCOperation_autoshieldcoinbase();

    // We don't want to be copied or moved around
    AsyncRPCOperation_autoshieldcoinbase(AsyncRPCOperation_autoshieldcoinbase const&) = delete;
    AsyncRPCOperation_autoshieldcoinbase(AsyncRPCOperation_autoshieldcoinbase&&) = delete;
    AsyncRPCOperation_autoshieldcoinbase& operator=(AsyncRPCOperation_autoshieldcoinbase const&) = delete;
    AsyncRPCOperation_autoshieldcoinbase& operator=(AsyncRPCOperation_autoshieldcoinbase&&) = delete;

    virtual void main();
    virtual void cancel();
    virtual UniValue getStatus() const;

private:
    int targetHeight_;
    int numTxCreated_        = 0;
    CAmount amountShielded_  = 0;
    std::vector<std::string> shieldTxIds_;

    bool main_impl();

    // Resolve a spendable, wallet-owned Sapling destination: the configured
    // -autoshieldaddress if set, else the first spendable z-addr the wallet
    // holds, else a freshly generated one (requires an unlocked wallet).
    // Returns false if none is available (e.g. locked wallet with no z-addr).
    bool resolveDestination(libzcash::SaplingPaymentAddress& destOut, std::string& destStrOut);

    void setResult();
};

#endif /* ASYNCRPCOPERATION_AUTOSHIELDCOINBASE_H */
