#pragma once

#include "core/types.hpp"

#include <hive/protocol/authority_trace_data.hpp>

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

namespace cpp {

/** Helper interface instance to allow integration of TS/JS/Python environment and override (implement) a virtual methods
*   to provide data to underlying C++ algoruthms.
*/
class IAccountAuthorityProvider
{
public:
  /** Allows to query for given account authority and specific role (owner, active, posting).
  */
  virtual std::optional<wax_authority> getAuthority(std::string account_name, std::string authorityRole) = 0;
  /// Allows to query for given witness signing key.
  virtual std::optional<std::string> getWitnessPublicKey(std::string witness_name) = 0;

  virtual ~IAccountAuthorityProvider() = default;
};

/** Common implementation of protocol interface, next exposed to other languages
    It provides Hive protocol functionality operating on Hive native JSON format.
*/
template <class FoundationProvider>
class protocol_impl : public FoundationProvider
{
public:
  using required_authority_collection_t = typename FoundationProvider::required_authority_collection_t;

  std::vector<std::string> cpp_operation_get_impacted_accounts(const std::string& operation) const;
  std::vector<std::string> cpp_transaction_get_impacted_accounts(const std::string& transaction) const;

  binary_data cpp_generate_binary_transaction_metadata(const std::string& transaction, bool use_hf26_serialization, bool strip_to_unsigned_transaction)const;
  binary_data cpp_generate_binary_operation_metadata(const std::string& operation, bool use_hf26_serialization)const;

  result cpp_validate_operation(const std::string& operation);
  result cpp_validate_transaction(const std::string& transaction);
  
  ///  Allows to calculate hf26 compliant transaction-id (serialized using hf26 form)
  result cpp_calculate_transaction_id(const std::string& transaction);
  /**  Allows to calculate legacy transaction-id (serialized using pre-hf26 form)
  *    This method is provided only to make possible verification of old Hive transaction ids (read from blocks produced before hf26).
  */
  result cpp_calculate_legacy_transaction_id(const std::string& transaction);

  ///  Allows to calculate hf26 compliant sig-digest (serialized using hf26 form)
  result cpp_calculate_sig_digest(const std::string& transaction, const std::string& chain_id);

  ///  Allows to calculate legacy sig-digest (serialized using pre-hf26 form)
  result cpp_calculate_legacy_sig_digest(const std::string& transaction, const std::string& chain_id);

  /** Allows to perform binary serialization of specified transaction.
  *   Uses HF26 serialization form.
  *
  *  @param transaction - JSON form of transaction to serialize
  *  @param strip_to_unsigned_transaction - if true, then only unsigned part of transaction will be serialized (signature container is always stripped)
  */
  result cpp_serialize_transaction(const std::string& transaction, bool strip_to_unsigned_transaction);

  /** Allows to restore a transaction object from HF26 binary serialization form.
  *   Returns a JSON form of deserialized transaction.
  */
  result cpp_deserialize_transaction(const std::string& transaction);

  /** Allows to collect all authorities required to process given transaction (needed to correctly sign it)
  *   Can throw on error.
  */
  required_authority_collection_t cpp_collect_transaction_required_authorities(const std::string& transaction);

  /** Allows to perform traced verify_authority call, and collect data gathered during analysis, returned through authority_verification_trace object.
  */
  hive::protocol::authority_verification_trace cpp_trace_authority_verification(
    const required_authority_collection_t& required_authorities,
    const std::vector<std::string>& decodedSignaturePublicKeys,
    IAccountAuthorityProvider& authorityProvider);

  /** Allows to collect signing keys from given transaction
  *   Can throw on error.
  */
  std::vector<std::string> cpp_collect_signing_keys(const std::string& transaction, retrieve_authorities_cb_t retrieve_authorities_cb,
    void* retrieve_authorities_fn);

  /** Minimize required signatures collection depend on given available keys and authorities.
  */
  std::vector<std::string> cpp_minimize_required_signatures(const std::string& signed_transaction, const minimize_required_signatures_data_t& minimize_required_signatures_data);

};

} /// namespace cpp
