/*
   This file is part of TALER
   Copyright (C) 2025 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/taler-exchange/reserves_get.h
 * @brief C interface for the GET /reserves/$RESERVE_PUB endpoint
 * @author Christian Grothoff
 */
#ifndef _TALER_EXCHANGE__RESERVES_GET_H
#define _TALER_EXCHANGE__RESERVES_GET_H

#include <taler/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;

  /**
   * 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 withdraw operation with age-restriction.
     * @e type is #TALER_EXCHANGE_RTT_WITHDRAWAL.
     */
    struct
    {
      /**
       * Signature authorizing the withdrawal for outgoing transaction.
       */
      json_t *out_authorization_sig;

      /**
       * The running hash over all hashes of blinded planchets of the withrdawal
       */
      struct TALER_HashBlindedPlanchetsP planchets_h;

      /**
       * If age restriction was required during the protocol
       */
      bool age_restricted;

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

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

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

      /**
       * True, if no blinding_seed was provided.  The value of
       * @e blinding_seed is then zero.
       */
      bool no_blinding_seed;

      /**
       * In case of denominations of cipher type Clause-Schnorr, the
       * seed for the prior call to /blinding-prepare
       */
      struct TALER_BlindingMasterSeedP blinding_seed;

      /**
       * Fee that was 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 the coin of type
       * #TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP.
       */
      struct TALER_ExchangeSignatureP exchange_sig;

      /**
       * Public key of the exchange that was 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_CLOSE.
     */
    struct
    {
      /**
       * Receiver account information for the outgoing wire transfer as a payto://-URI.
       */
      struct TALER_FullPayto receiver_account_details;

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

      /**
       * Signature of the coin of type
       * #TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED.
       */
      struct TALER_ExchangeSignatureP exchange_sig;

      /**
       * Public key of the exchange that was used for @e exchange_sig.
       */
      struct TALER_ExchangePublicKeyP exchange_pub;

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

      /**
       * Fee that was 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.
       * (Determines amount to be paid.)
       */
      struct GNUNET_TIME_Timestamp reserve_expiration;

      /**
       * How many open purses should be included with the
       * open reserve?
       * (Determines amount to be paid.)
       */
      uint32_t purse_limit;

    } open_request;

    /**
     * Information about an 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;

};


/**
 * @brief A /reserves/ GET Handle
 */
struct TALER_EXCHANGE_ReservesGetHandle;


/**
 * @brief Reserve summary.
 */
struct TALER_EXCHANGE_ReserveSummary
{

  /**
   * High-level HTTP response details.
   */
  struct TALER_EXCHANGE_HttpResponse hr;

  /**
   * Details depending on @e hr.http_status.
   */
  union
  {

    /**
     * Information returned on success, if
     * @e hr.http_status is #MHD_HTTP_OK
     */
    struct
    {

      /**
       * Reserve balance.
       */
      struct TALER_Amount balance;

      /**
       * payto://-URI of the last bank account that wired funds
       * to the reserve, NULL for none (can happen if reserve
       * was funded via P2P merge).
       */
      struct TALER_FullPayto last_origin;
    } ok;

  } details;

};


/**
 * Callbacks of this type are used to serve the result of submitting a
 * reserve status request to a exchange.
 *
 * @param cls closure
 * @param rs HTTP response data
 */
typedef void
(*TALER_EXCHANGE_ReservesGetCallback) (
  void *cls,
  const struct TALER_EXCHANGE_ReserveSummary *rs);


/**
 * Submit a request to obtain the transaction history of a reserve
 * from the exchange.  Note that while we return the full response to the
 * caller for further processing, we do already verify that the
 * response is well-formed (i.e. that signatures included in the
 * response are all valid and add up to the balance).  If the exchange's
 * reply is not well-formed, we return an HTTP status code of zero to
 * @a cb.
 *
 * @param ctx curl context
 * @param url exchange base URL
 * @param reserve_pub public key of the reserve to inspect
 * @param timeout how long to wait for an affirmative reply
 *        (enables long polling if the reserve does not yet exist)
 * @param cb the callback to call when a reply for this request is available
 * @param cb_cls closure for the above callback
 * @return a handle for this request; NULL if the inputs are invalid (i.e.
 *         signatures fail to verify).  In this case, the callback is not called.
 */
struct TALER_EXCHANGE_ReservesGetHandle *
TALER_EXCHANGE_reserves_get (
  struct GNUNET_CURL_Context *ctx,
  const char *url,
  const struct TALER_ReservePublicKeyP *reserve_pub,
  struct GNUNET_TIME_Relative timeout,
  TALER_EXCHANGE_ReservesGetCallback cb,
  void *cb_cls);


/**
 * Cancel a reserve GET request.  This function cannot be used
 * on a request handle if a response is already served for it.
 *
 * @param rgh the reserve request handle
 */
void
TALER_EXCHANGE_reserves_get_cancel (
  struct TALER_EXCHANGE_ReservesGetHandle *rgh);

#endif
