#pragma once

#include <xrpl/core/PeerReservationTable.h>
#include <xrpl/rdb/DatabaseCon.h>
#include <xrpl/server/Manifest.h>

namespace xrpl {

/**
 * @brief makeWalletDB Opens the wallet database and returns it.
 * @param setup Path to the database and other opening parameters.
 * @param j Journal.
 * @return Unique pointer to the database descriptor.
 */
std::unique_ptr<DatabaseCon>
makeWalletDB(DatabaseCon::Setup const& setup, beast::Journal j);

/**
 * @brief makeTestWalletDB Opens a test wallet database with an arbitrary name.
 * @param setup Path to the database and other opening parameters.
 * @param dbname Name of the database.
 * @param j Journal.
 * @return Unique pointer to the database descriptor.
 */
std::unique_ptr<DatabaseCon>
makeTestWalletDB(DatabaseCon::Setup const& setup, std::string const& dbname, beast::Journal j);

/**
 * @brief getManifests Loads a manifest from the wallet database and stores it
 *        in the cache.
 * @param session Session with the database.
 * @param dbTable Name of the database table from which the manifest will be
 *        extracted.
 * @param mCache Cache for storing the manifest.
 * @param j Journal.
 */
void
getManifests(
    soci::session& session,
    std::string const& dbTable,
    ManifestCache& mCache,
    beast::Journal j);

/**
 * @brief saveManifests Saves all given manifests to the database.
 * @param session Session with the database.
 * @param dbTable Name of the database table that will store the manifest.
 * @param isTrusted Callback that returns true if the key is trusted.
 * @param map Maps public keys to manifests.
 * @param j Journal.
 */
void
saveManifests(
    soci::session& session,
    std::string const& dbTable,
    std::function<bool(PublicKey const&)> const& isTrusted,
    hash_map<PublicKey, Manifest> const& map,
    beast::Journal j);

/**
 * @brief addValidatorManifest Saves the manifest of a validator to the
 *        database.
 * @param session Session with the database.
 * @param serialized Manifest of the validator in raw format.
 */
void
addValidatorManifest(soci::session& session, std::string const& serialized);

/** Delete any saved public/private key associated with this node. */
void
clearNodeIdentity(soci::session& session);

/** Returns a stable public and private key for this node.

    The node's public identity is defined by a secp256k1 keypair
    that is (normally) randomly generated. This function will
    return such a keypair, securely generating one if needed.

    @param session Session with the database.

    @return Pair of public and private secp256k1 keys.
 */
std::pair<PublicKey, SecretKey>
getNodeIdentity(soci::session& session);

/**
 * @brief getPeerReservationTable Returns the peer reservation table.
 * @param session Session with the database.
 * @param j Journal.
 * @return Peer reservation hash table.
 */
std::unordered_set<PeerReservation, beast::uhash<>, KeyEqual>
getPeerReservationTable(soci::session& session, beast::Journal j);

/**
 * @brief insertPeerReservation Adds an entry to the peer reservation table.
 * @param session Session with the database.
 * @param nodeId Public key of the node.
 * @param description Description of the node.
 */
void
insertPeerReservation(
    soci::session& session,
    PublicKey const& nodeId,
    std::string const& description);

/**
 * @brief deletePeerReservation Deletes an entry from the peer reservation
 *        table.
 * @param session Session with the database.
 * @param nodeId Public key of the node to remove.
 */
void
deletePeerReservation(soci::session& session, PublicKey const& nodeId);

/**
 * @brief createFeatureVotes Creates the FeatureVote table if it does not exist.
 * @param session Session with the wallet database.
 * @return true if the table already exists
 */
bool
createFeatureVotes(soci::session& session);

// For historical reasons the up-vote and down-vote integer representations
// are unintuitive.
enum class AmendmentVote : int { obsolete = -1, up = 0, down = 1 };

/**
 * @brief readAmendments Reads all amendments from the FeatureVotes table.
 * @param session Session with the wallet database.
 * @param callback Callback called for each amendment with its hash, name and
 *        optionally a flag denoting whether the amendment should be vetoed.
 */
void
readAmendments(
    soci::session& session,
    std::function<void(
        boost::optional<std::string> amendment_hash,
        boost::optional<std::string> amendment_name,
        boost::optional<AmendmentVote> vote)> const& callback);

/**
 * @brief voteAmendment Set the veto value for a particular amendment.
 * @param session Session with the wallet database.
 * @param amendment Hash of the amendment.
 * @param name Name of the amendment.
 * @param vote Whether to vote in favor of this amendment.
 */
void
voteAmendment(
    soci::session& session,
    uint256 const& amendment,
    std::string const& name,
    AmendmentVote vote);

}  // namespace xrpl
