#pragma once

#include <cstdint>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <map>
#include <optional>
#include <vector>

namespace cpp {

enum error_code { fail = 0, ok = 1 };

struct result
{
  error_code value = error_code::ok;

  std::string content;
  std::string exception_message;

  result() noexcept = default;
};

struct private_key_data
{
  std::string wif_private_key;
  std::string associated_public_key;
};

struct brain_key_data
{
  /// List of N (atm 16) space separated words generated by suggest_brain_key function
  std::string brain_key;
  /// First private key derived from brain key
  std::string wif_private_key;
  std::string associated_public_key;
};

struct json_asset
{
  std::string amount;
  uint32_t    precision=0;
  std::string nai;

  json_asset() = default;
  json_asset(const std::string& _amount, uint32_t _precision, const std::string& _nai)
    : amount(_amount), precision(_precision), nai(_nai) {}
};

struct json_price
{
  json_asset base;
  json_asset quote;
};

struct crypto_memo
{
  /** Base58 encoded string representing a PUBLIC key identifying a PRIVATE key used for encryption.
  *   Does NOT contain prefix (STM)
  */
  std::string _from;
  /** Base58 encoded string representing a second PUBLIC key used used at encryption.
      Allows to use also this second PRIVATE key to decrypt the content.
  *   Does NOT contain prefix (STM)
  */
  std::string to;

  /** Base58 encoded encrypted content.
  */
  std::string content;

  crypto_memo() = default;
  crypto_memo(const std::string& from, const std::string& to, const std::string& content)
    : _from(from), to(to), content(content) {}
};

struct ref_block_data
{
  uint16_t ref_block_num;
  uint32_t ref_block_prefix;
};

struct witness_set_properties_data
{
  /** Witness key to match the current witness key */
  std::string                key;
  /** New witness key to set */
  std::optional<std::string> new_signing_key;
  /** HIVE maximum account creation fee */
  std::optional<json_asset>  account_creation_fee;
  /** New witness URL to set */
  std::optional<std::string> url;
  /** HBD to HIVE ratio proposed by the witness */
  std::optional<json_price>       hbd_exchange_rate;
  /** This witnesses vote for the maximum_block_size which is used by the network to tune rate limiting and capacity */
  std::optional<uint32_t>    maximum_block_size;
  /** Rate of interest for holding HBD (in BPS - basis points) */
  std::optional<uint16_t>    hbd_interest_rate;
  /** How many free accounts should be created per elected witness block. Scaled so that HIVE_ACCOUNT_SUBSIDY_PRECISION represents one account. */
  std::optional<int32_t>     account_subsidy_budget;
  /** What fraction of the "stockpiled" free accounts "expire" per elected witness block. Scaled so that 1 << HIVE_RD_DECAY_DENOM_SHIFT represents 100% of accounts expiring. */
  std::optional<uint32_t>    account_subsidy_decay;
};

using witness_set_properties_serialized = std::map<std::string, std::string>;

struct wax_authority
{
  using authority_map = std::map<std::string, uint16_t>;

  uint32_t      weight_threshold = 0;
  authority_map account_auths;
  authority_map key_auths;
};

struct required_authority_collection
{
  typedef std::set<std::string> account_set;
  typedef account_set account_collection_t;

  account_set posting_accounts;
  account_set active_accounts;
  account_set owner_accounts;
  std::vector<wax_authority> other_authorities;
};

struct wax_authorities
{
  wax_authority active;
  wax_authority owner;
  wax_authority posting;
};

struct binary_data_node
{
  std::string key;
  std::string type;
  uint32_t    offset=0;
  uint32_t    size=0;
  std::string value;
  uint32_t    length = 0;
  std::vector<binary_data_node> children;
};

struct binary_data
{
  std::string binary;
  std::vector<binary_data_node> offsets;
};

using wax_authorities_map_t = std::map<std::string, wax_authorities>;
typedef wax_authorities_map_t (*retrieve_authorities_cb_t)(std::vector<std::string>, void*);
typedef std::string (*witness_public_key_getter_cb_t)(std::string, void*);

struct minimize_required_signatures_data_t
{
  std::string chain_id;
  std::vector<std::string> available_keys;
  wax_authorities_map_t authorities_map;
  witness_public_key_getter_cb_t get_witness_key_cb;
  void* get_witness_key_fn;
  std::optional<uint32_t> max_recursion;
  std::optional<uint32_t> max_membership;
  std::optional<uint32_t> max_account_auths;
  bool allow_strict_and_mixed_authorities = false;
};

} /// namespace cpp
