/*
  This file is part of TALER
  (C) 2014-2023 Taler Systems SA

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
  Foundation; either version 3, or (at your option) any later version.

  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file taler-merchant-httpd_exchanges.h
 * @brief logic this HTTPD keeps for each exchange we interact with
 * @author Marcello Stanisci
 * @author Christian Grothoff
 */
#ifndef TALER_MERCHANT_HTTPD_EXCHANGES_H
#define TALER_MERCHANT_HTTPD_EXCHANGES_H

#include <jansson.h>
#include <gnunet/gnunet_util_lib.h>
#include <curl/curl.h>
#include <taler/taler_util.h>
#include <taler/taler_exchange_service.h>
#include "taler-merchant-httpd.h"


/**
 * Exchange
 */
struct TMH_Exchange;


/**
 * Parses "trusted" exchanges listed in the configuration.
 *
 * @param cfg the configuration
 * @return number of trusted exchanges on success; #GNUNET_SYSERR upon error in
 *          parsing.
 */
enum GNUNET_GenericReturnValue
TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg);


/**
 * Function called to shutdown the exchanges subsystem.
 */
void
TMH_EXCHANGES_done (void);


/**
 * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
 * operation.
 *
 * @param cls closure
 * @param keys the keys of the exchange
 * @param exchange representation of the exchange
 */
typedef void
(*TMH_EXCHANGES_Find2Continuation)(
  void *cls,
  struct TALER_EXCHANGE_Keys *keys,
  struct TMH_Exchange *exchange);


/**
 * Information we keep for a pending #MMH_EXCHANGES_keys4exchange() operation.
 */
struct TMH_EXCHANGES_KeysOperation;


/**
 * Check if we trust the exchange at @a exchange_url.
 *
 * @param exchange_url exchange base url to check
 * @return true if we trust that exchange (assuming the master
 *   public key matches)
 */
bool
TMH_EXCHANGES_check_trusted (
  const char *exchange_url);


/**
 * Get /keys of the given @a exchange.
 *
 * @param exchange URL of the exchange we would like to talk to
 * @param force_download force /keys download now
 * @param fc function to call with the handles for the exchange
 * @param fc_cls closure for @a fc
 */
struct TMH_EXCHANGES_KeysOperation *
TMH_EXCHANGES_keys4exchange (
  const char *exchange,
  bool force_download,
  TMH_EXCHANGES_Find2Continuation fc,
  void *fc_cls);


/**
 * Abort pending keys details lookup operation.
 *
 * @param fo handle to operation to abort
 */
void
TMH_EXCHANGES_keys4exchange_cancel (struct TMH_EXCHANGES_KeysOperation *fo);


/**
 * Callback on an exchange known to us. Does not warrant
 * that the "keys" information is actually available for
 * @a exchange.
 *
 * @param cls closure
 * @param url base URL of the exchange
 * @param exchange internal handle for the exchange
 */
typedef void
(*TMH_ExchangeCallback)(void *cls,
                        const char *url,
                        const struct TMH_Exchange *exchange);


/**
 * Return all trusted exchanges to @a cb.
 *
 * @param cb function to call
 * @param cb_cls closure for @a cb
 */
void
TMH_exchange_get_trusted (TMH_ExchangeCallback cb,
                          void *cb_cls);


/**
 * Return the master public key of the given @a exchange.
 * Will be returned from configuration for trusted
 * exchanges.
 *
 * @param exchange exchange to get master public key for
 * @return the master public key of @a exchange
 */
const struct TALER_MasterPublicKeyP *
TMH_EXCHANGES_get_master_pub (
  const struct TMH_Exchange *exchange);


/**
 * Return the currency of the given @a exchange.
 * Will be returned from configuration for trusted
 * exchanges.
 *
 * @param exchange exchange to get master public key for
 * @return the currency of @a exchange
 */
const char *
TMH_EXCHANGES_get_currency (
  const struct TMH_Exchange *exchange);


/**
 * Check if the given operation and amount would
 * violate any hard limits of the exchange.
 * Only useful for transaction and refund limits.
 *
 * @param keys the keys of the exchange to check limit for
 * @param operation_type the kind of operation we perform
 * @param amount the amount we want to transact
 * @return true if this is allowed
 */
bool
TMH_EXCHANGES_is_below_limit (
  const struct TALER_EXCHANGE_Keys *keys,
  enum TALER_KYCLOGIC_KycTriggerEvent operation_type,
  const struct TALER_Amount *amount);


/**
 * Lookup current wire fee by @a exchange_url and @a wire_method.
 *
 * @param exchange the exchange to check
 * @param wire_method wire method to lookup fee by
 * @param[out] wire_fee set to the wire fee
 * @return #GNUNET_OK on success
 *         #GNUNET_NO if @a wire_method is not supported
 *         #GNUNET_SYSERR if @a exchange_url did not yet respond properly to our /wire request
 */
enum GNUNET_GenericReturnValue
TMH_EXCHANGES_lookup_wire_fee (
  const struct TMH_Exchange *exchange,
  const char *wire_method,
  struct TALER_Amount *wire_fee);


/**
 * Check if we would trust @a ex to deposit funds into our account @a
 * wm. Checks that both @a ex is trusted and that @a ex allows wire transfers
 * into the account given in @a wm.
 *
 * @param instance_id the instance to check for
 * @param exchange the exchange to check
 * @param wm the wire method to check with
 * @param[in,out] max_amount maximum amount we may deposit at this
 *    exchange; input is an existing maximum, that
 *    can be lowered by this function due to transaction
 *    limits and deposit limits of the exchange
 * @return #TMH_ES_OK if such a debit can happen
 *         #TMH_ES_NO_ACC if the exchange cannot
 *            be used due to account restrictions
 *         #TMH_ES_NO_CURR if the exchange cannot be used
 *            because it is for a different currency
 *         #TMH_ES_NO_KEYS if the exchange cannot be used
 *            because we do not even know its keys
 *         #TMH_ES_RETRY_OK if the exchange keys request
 *            could be retried (OR-bit!)
 */
enum TMH_ExchangeStatus
{
  TMH_ES_OK = 0,
  TMH_ES_NO_ACC = 1,
  TMH_ES_NO_CURR = 2,
  TMH_ES_NO_KEYS = 3,
  TMH_ES_RETRY_OK = 16,
  TMH_ES_NO_ACC_RETRY_OK = TMH_ES_NO_ACC | TMH_ES_RETRY_OK,
  TMH_ES_NO_CURR_RETRY_OK = TMH_ES_NO_CURR | TMH_ES_RETRY_OK,
  TMH_ES_NO_KEYS_RETRY_OK = TMH_ES_NO_KEYS | TMH_ES_RETRY_OK,
}
TMH_exchange_check_debit (
  const char *instance_id,
  const struct TMH_Exchange *exchange,
  const struct TMH_WireMethod *wm,
  struct TALER_Amount *max_amount);


/**
 * Check if we support the given currency (by having an
 * exchange configured with it).
 *
 * @param currency currency to check
 * @return true if the currency is supported
 */
bool
TMH_test_exchange_configured_for_currency (
  const char *currency);


/**
 * Determines the legal limit for a given @a operation_type
 * at a given @a exchange_url.
 *
 * @param exchange_url base URL of the exchange to get
 *   the refund limit for
 * @param operation_type type of operation
 * @param[in,out] amount lowered to the maximum
 *   allowed at the exchange
 */
void
TMH_EXCHANGES_get_limit (
  const char *exchange_url,
  enum TALER_KYCLOGIC_KycTriggerEvent operation_type,
  struct TALER_Amount *amount);

#endif
