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

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU Affero 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
/**
 * @file include/taler/exchange/get-reserves-RESERVE_PUB-history.h
 * @brief C interface for GET /reserves/$RESERVE_PUB/history
 * @author Christian Grothoff
 */
#ifndef _TALER_EXCHANGE__GET_RESERVES_RESERVE_PUB_HISTORY_H
#define _TALER_EXCHANGE__GET_RESERVES_RESERVE_PUB_HISTORY_H

#include <taler/exchange/common.h>


/**
 * Ways how a reserve's balance may change.
 */
enum TALER_EXCHANGE_ReserveTransactionType
{

  /**
   * Deposit into the reserve.
   */
  TALER_EXCHANGE_RTT_CREDIT,

  /**
   * Withdrawal from the reserve.
   */
  TALER_EXCHANGE_RTT_WITHDRAWAL,

  /**
   * /recoup operation.
   */
  TALER_EXCHANGE_RTT_RECOUP,

  /**
   * Reserve closed operation.
   */
  TALER_EXCHANGE_RTT_CLOSING,

  /**
   * Reserve purse merge operation.
   */
  TALER_EXCHANGE_RTT_MERGE,

  /**
   * Reserve open request operation.
   */
  TALER_EXCHANGE_RTT_OPEN,

  /**
   * Reserve close request operation.
   */
  TALER_EXCHANGE_RTT_CLOSE

};


/**
 * @brief Entry in the reserve's transaction history.
 */
struct TALER_EXCHANGE_ReserveHistoryEntry
{

  /**
   * Type of the transaction.
   */
  enum TALER_EXCHANGE_ReserveTransactionType type;

  /**
   * Offset of this entry in the reserve history.
   * Useful to request incremental histories via
   * the "start" query parameter.
   */
  uint64_t history_offset;

  /**
   * Amount transferred (in or out).
   */
  struct TALER_Amount amount;

  /**
   * Details depending on @e type.
   */
  union
  {

    /**
     * Information about a deposit that filled this reserve.
     * @e type is #TALER_EXCHANGE_RTT_CREDIT.
     */
    struct
    {
      /**
       * Sender account payto://-URL of the incoming transfer.
       */
      struct TALER_FullPayto sender_url;

      /**
       * Information that uniquely identifies the wire transfer.
       */
      uint64_t wire_reference;

      /**
       * When did the wire transfer happen?
       */
      struct GNUNET_TIME_Timestamp timestamp;

    } in_details;

    /**
     * Information about a withdrawal operation.
     * @e type is #TALER_EXCHANGE_RTT_WITHDRAWAL.
     */
    struct
    {
      /**
       * Signature authorizing the withdrawal.
       */
      struct TALER_ReserveSignatureP reserve_sig;

      /**
       * Running hash over all hashes of blinded planchets of the withdrawal.
       */
      struct TALER_HashBlindedPlanchetsP planchets_h;

      /**
       * True if age restriction was required during the protocol.
       */
      bool age_restricted;

      /**
       * Maximum age committed, if @e age_restricted is true.
       */
      uint8_t max_age;

      /**
       * If @e age_restricted is true, the index not to be revealed
       * after the initial commitment in /withdraw.
       */
      uint8_t noreveal_index;

      /**
       * If @e age_restricted is true, hash of the selected blinded planchets.
       */
      struct TALER_HashBlindedPlanchetsP selected_h;

      /**
       * True if no blinding_seed was provided.
       */
      bool no_blinding_seed;

      /**
       * For CS denominations, the seed for the prior /blinding-prepare call.
       */
      struct TALER_BlindingMasterSeedP blinding_seed;

      /**
       * Fee charged for the withdrawal.
       */
      struct TALER_Amount fee;

      /**
       * Number of coins withdrawn.
       */
      uint16_t num_coins;

    } withdraw;

    /**
     * Information provided if the reserve was filled via /recoup.
     * @e type is #TALER_EXCHANGE_RTT_RECOUP.
     */
    struct
    {
      /**
       * Public key of the coin that was paid back.
       */
      struct TALER_CoinSpendPublicKeyP coin_pub;

      /**
       * Signature of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP.
       */
      struct TALER_ExchangeSignatureP exchange_sig;

      /**
       * Public key used for @e exchange_sig.
       */
      struct TALER_ExchangePublicKeyP exchange_pub;

      /**
       * When did the /recoup operation happen?
       */
      struct GNUNET_TIME_Timestamp timestamp;

    } recoup_details;

    /**
     * Information about a close operation of the reserve.
     * @e type is #TALER_EXCHANGE_RTT_CLOSING.
     */
    struct
    {
      /**
       * Receiver account for the outgoing wire transfer.
       */
      struct TALER_FullPayto receiver_account_details;

      /**
       * Wire transfer details for the outgoing wire transfer.
       */
      struct TALER_WireTransferIdentifierRawP wtid;

      /**
       * Signature of type TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED.
       */
      struct TALER_ExchangeSignatureP exchange_sig;

      /**
       * Public key used for @e exchange_sig.
       */
      struct TALER_ExchangePublicKeyP exchange_pub;

      /**
       * When did the wire transfer happen?
       */
      struct GNUNET_TIME_Timestamp timestamp;

      /**
       * Fee charged for the closing.
       */
      struct TALER_Amount fee;

    } close_details;

    /**
     * Information about a merge operation on the reserve.
     * @e type is #TALER_EXCHANGE_RTT_MERGE.
     */
    struct
    {
      /**
       * Fee paid for the purse.
       */
      struct TALER_Amount purse_fee;

      /**
       * Hash over the contract.
       */
      struct TALER_PrivateContractHashP h_contract_terms;

      /**
       * Merge capability key.
       */
      struct TALER_PurseMergePublicKeyP merge_pub;

      /**
       * Purse public key.
       */
      struct TALER_PurseContractPublicKeyP purse_pub;

      /**
       * Signature by the reserve approving the merge.
       */
      struct TALER_ReserveSignatureP reserve_sig;

      /**
       * When was the merge made?
       */
      struct GNUNET_TIME_Timestamp merge_timestamp;

      /**
       * When was the purse set to expire?
       */
      struct GNUNET_TIME_Timestamp purse_expiration;

      /**
       * Minimum age required for depositing into the purse.
       */
      uint32_t min_age;

      /**
       * Flags of the purse.
       */
      enum TALER_WalletAccountMergeFlags flags;

      /**
       * True if the purse was actually merged, false if only the
       * @e purse_fee was charged.
       */
      bool merged;

    } merge_details;

    /**
     * Information about an open request operation on the reserve.
     * @e type is #TALER_EXCHANGE_RTT_OPEN.
     */
    struct
    {
      /**
       * Signature by the reserve approving the open.
       */
      struct TALER_ReserveSignatureP reserve_sig;

      /**
       * Amount to be paid from the reserve balance to open the reserve.
       */
      struct TALER_Amount reserve_payment;

      /**
       * When was the request created?
       */
      struct GNUNET_TIME_Timestamp request_timestamp;

      /**
       * For how long should the reserve be kept open?
       */
      struct GNUNET_TIME_Timestamp reserve_expiration;

      /**
       * How many open purses should be included with the open reserve?
       */
      uint32_t purse_limit;

    } open_request;

    /**
     * Information about a close request operation on the reserve.
     * @e type is #TALER_EXCHANGE_RTT_CLOSE.
     */
    struct
    {
      /**
       * Signature by the reserve approving the close.
       */
      struct TALER_ReserveSignatureP reserve_sig;

      /**
       * When was the request created?
       */
      struct GNUNET_TIME_Timestamp request_timestamp;

      /**
       * Hash of the payto://-URI of the target account for the closure,
       * or all zeros for the reserve origin account.
       */
      struct TALER_FullPaytoHashP target_account_h_payto;

    } close_request;

  } details;

};


/**
 * Possible options we can set for the GET reserves history request.
 */
enum TALER_EXCHANGE_GetReservesHistoryOption
{
  /**
   * End of list of options.
   */
  TALER_EXCHANGE_GET_RESERVES_HISTORY_OPTION_END = 0,

  /**
   * Only return entries with offset strictly greater than this value.
   * Defaults to 0 (return all entries).
   * The offset corresponds to the etag / last entry offset from a
   * previous response.
   */
  TALER_EXCHANGE_GET_RESERVES_HISTORY_OPTION_START_OFF

};


/**
 * Value for an option for the GET reserves history request.
 */
struct TALER_EXCHANGE_GetReservesHistoryOptionValue
{
  /**
   * Type of the option being set.
   */
  enum TALER_EXCHANGE_GetReservesHistoryOption option;

  /**
   * Specific option value.
   */
  union
  {
    /**
     * Value if @e option is TALER_EXCHANGE_GET_RESERVES_HISTORY_OPTION_START_OFF.
     */
    uint64_t start_off;

  } details;

};


/**
 * Handle for an operation to GET /reserves/$RESERVE_PUB/history.
 */
struct TALER_EXCHANGE_GetReservesHistoryHandle;


/**
 * Set up GET /reserves/$RESERVE_PUB/history operation.
 * Note that you must explicitly start the operation after
 * possibly setting options.
 *
 * @param ctx the context
 * @param url base URL of the exchange
 * @param keys exchange keys for signature verification
 * @param reserve_priv private key of the reserve to inspect
 * @return handle to operation
 */
struct TALER_EXCHANGE_GetReservesHistoryHandle *
TALER_EXCHANGE_get_reserves_history_create (
  struct GNUNET_CURL_Context *ctx,
  const char *url,
  struct TALER_EXCHANGE_Keys *keys,
  const struct TALER_ReservePrivateKeyP *reserve_priv);


/**
 * Terminate the list of options.
 *
 * @return the terminating object of struct TALER_EXCHANGE_GetReservesHistoryOptionValue
 */
#define TALER_EXCHANGE_get_reserves_history_option_end_()                   \
        (const struct TALER_EXCHANGE_GetReservesHistoryOptionValue)         \
        {                                                                    \
          .option = TALER_EXCHANGE_GET_RESERVES_HISTORY_OPTION_END          \
        }

/**
 * Set starting offset for partial history fetch.
 *
 * @param o offset: only return entries with offset > this value.
 *          Use the etag value from a previous response.
 * @return representation of the option as a struct TALER_EXCHANGE_GetReservesHistoryOptionValue
 */
#define TALER_EXCHANGE_get_reserves_history_option_start_off(o)              \
        (const struct TALER_EXCHANGE_GetReservesHistoryOptionValue)          \
        {                                                                     \
          .option = TALER_EXCHANGE_GET_RESERVES_HISTORY_OPTION_START_OFF,    \
          .details.start_off = (o)                                            \
        }


/**
 * Set the requested options for the operation.
 *
 * If any option fails, other options may or may not be applied.
 *
 * @param grhh the request to set the options for
 * @param num_options length of the @a options array
 * @param options an array of options
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_get_reserves_history_set_options_ (
  struct TALER_EXCHANGE_GetReservesHistoryHandle *grhh,
  unsigned int num_options,
  const struct TALER_EXCHANGE_GetReservesHistoryOptionValue *options);


/**
 * Set the requested options for the operation.
 *
 * If any option fails, other options may or may not be applied.
 *
 * It should be used with helpers that create required options, for example:
 *
 * TALER_EXCHANGE_get_reserves_history_set_options (
 *   grhh,
 *   TALER_EXCHANGE_get_reserves_history_option_start_off (last_etag));
 *
 * @param grhh the request to set the options for
 * @param ... the list of options, each created by a
 *            TALER_EXCHANGE_get_reserves_history_option_NAME(VALUE) helper
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
#define TALER_EXCHANGE_get_reserves_history_set_options(grhh,...)              \
        TALER_EXCHANGE_get_reserves_history_set_options_ (                     \
          grhh,                                                                 \
          TALER_EXCHANGE_COMMON_OPTIONS_ARRAY_MAX_SIZE,                        \
          ((const struct TALER_EXCHANGE_GetReservesHistoryOptionValue[])       \
           {__VA_ARGS__,                                                        \
            TALER_EXCHANGE_get_reserves_history_option_end_ () }               \
          ))


/**
 * @brief Reserve history response.
 */
struct TALER_EXCHANGE_GetReservesHistoryResponse
{
  /**
   * HTTP response data.
   */
  struct TALER_EXCHANGE_HttpResponse hr;

  /**
   * Details depending on @e hr.http_status.
   */
  union
  {
    /**
     * Information returned on #MHD_HTTP_OK.
     */
    struct
    {
      /**
       * Current reserve balance.  May differ from total_in - total_out
       * if the history is truncated.
       */
      struct TALER_Amount balance;

      /**
       * Total of all inbound transactions in @e history.
       */
      struct TALER_Amount total_in;

      /**
       * Total of all outbound transactions in @e history.
       */
      struct TALER_Amount total_out;

      /**
       * Current etag / last entry offset in the history.
       * Use this as the start_off option for incremental fetches.
       * Offsets are not necessarily contiguous.
       */
      uint64_t etag;

      /**
       * Reserve transaction history.
       */
      const struct TALER_EXCHANGE_ReserveHistoryEntry *history;

      /**
       * Length of the @e history array.
       */
      size_t history_len;

    } ok;

  } details;

};


#ifndef TALER_EXCHANGE_GET_RESERVES_HISTORY_RESULT_CLOSURE
/**
 * Type of the closure used by
 * the #TALER_EXCHANGE_GetReservesHistoryCallback.
 */
#define TALER_EXCHANGE_GET_RESERVES_HISTORY_RESULT_CLOSURE void
#endif /* TALER_EXCHANGE_GET_RESERVES_HISTORY_RESULT_CLOSURE */

/**
 * Type of the function that receives the result of a
 * GET /reserves/$RESERVE_PUB/history request.
 *
 * @param cls closure
 * @param result result returned by the HTTP server
 */
typedef void
(*TALER_EXCHANGE_GetReservesHistoryCallback)(
  TALER_EXCHANGE_GET_RESERVES_HISTORY_RESULT_CLOSURE *cls,
  const struct TALER_EXCHANGE_GetReservesHistoryResponse *result);


/**
 * Start GET /reserves/$RESERVE_PUB/history operation.
 *
 * @param[in,out] grhh operation to start
 * @param cb function to call with the exchange's result
 * @param cb_cls closure for @a cb
 * @return status code, #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TALER_EXCHANGE_get_reserves_history_start (
  struct TALER_EXCHANGE_GetReservesHistoryHandle *grhh,
  TALER_EXCHANGE_GetReservesHistoryCallback cb,
  TALER_EXCHANGE_GET_RESERVES_HISTORY_RESULT_CLOSURE *cb_cls);


/**
 * Cancel GET /reserves/$RESERVE_PUB/history operation.  This function must
 * not be called by clients after the TALER_EXCHANGE_GetReservesHistoryCallback
 * has been invoked (as in those cases it'll be called internally by the
 * implementation already).
 *
 * @param[in] grhh operation to cancel
 */
void
TALER_EXCHANGE_get_reserves_history_cancel (
  struct TALER_EXCHANGE_GetReservesHistoryHandle *grhh);


#endif /* _TALER_EXCHANGE__GET_RESERVES_RESERVE_PUB_HISTORY_H */
