/*
  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/post-withdraw_blinded.h
 * @brief low-level C interface for POST /withdraw
 * @author Christian Grothoff
 */
#ifndef _TALER_EXCHANGE__POST_WITHDRAW_BLINDED_H
#define _TALER_EXCHANGE__POST_WITHDRAW_BLINDED_H

#include <taler/exchange/common.h>
#include <taler/exchange/post-withdraw.h>


/**
 * @brief Information needed to withdraw coins (low-level, pre-blinded).
 */
struct TALER_EXCHANGE_WithdrawBlindedCoinInput
{
  /**
   * The denomination of the coin.
   */
  const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;

  /**
   * Blinded planchet for a single coin.
   */
  struct TALER_PlanchetDetail planchet_details;
};

/**
 * @brief Information needed to withdraw age-restricted coins (low-level, pre-blinded).
 */
struct TALER_EXCHANGE_WithdrawBlindedAgeRestrictedCoinInput
{
  /**
   * The denomination of the coin.  MUST support age restriction.
   */
  const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;

  /**
   * Tuple of length kappa of planchet candidates for a single coin.
   */
  struct TALER_PlanchetDetail planchet_details[TALER_CNC_KAPPA];
};


/**
 * Handle for an operation to POST /withdraw (low-level, pre-blinded variant).
 */
struct TALER_EXCHANGE_PostWithdrawBlindedHandle;


/**
 * Set up POST /withdraw operation (low-level variant with pre-blinded
 * planchets).
 * Note that you must explicitly start the operation after setup.
 *
 * This variant does not do the blinding/unblinding and only
 * fetches the blind signatures on the already blinded planchets.
 *
 * For age-restricted coins requiring a proof, pass @a blinded_input as NULL
 * and supply the age-restricted input via the
 * #TALER_EXCHANGE_POST_WITHDRAW_BLINDED_OPTION_WITH_AGE_PROOF option.
 *
 * @param curl_ctx The curl context to use
 * @param keys The /keys material from the exchange
 * @param exchange_url The base-URL of the exchange
 * @param reserve_priv private key of the reserve to withdraw from
 * @param blinding_seed seed used for blinding of CS denominations, might be NULL
 * @param num_input number of entries in the @a blinded_input array
 * @param blinded_input array of planchet details to withdraw, or NULL if using WITH_AGE_PROOF option
 * @return handle to operation, NULL on error
 */
struct TALER_EXCHANGE_PostWithdrawBlindedHandle *
TALER_EXCHANGE_post_withdraw_blinded_create (
  struct GNUNET_CURL_Context *curl_ctx,
  struct TALER_EXCHANGE_Keys *keys,
  const char *exchange_url,
  const struct TALER_ReservePrivateKeyP *reserve_priv,
  const struct TALER_BlindingMasterSeedP *blinding_seed,
  size_t num_input,
  const struct TALER_EXCHANGE_WithdrawBlindedCoinInput *blinded_input);


/**
 * Possible options we can set for the POST /withdraw request
 * (low-level, pre-blinded variant).
 */
enum TALER_EXCHANGE_PostWithdrawBlindedOption
{
  /**
   * End of list of options.
   */
  TALER_EXCHANGE_POST_WITHDRAW_BLINDED_OPTION_END = 0,

  /**
   * Upgrade to an age-proof withdrawal for age-restricted coins, requiring
   * an additional call to POST /reveal-withdraw.
   * The @e details.with_age_proof.max_age field gives the maximum age to
   * (provably) commit to.
   * The @e details.with_age_proof.input field gives the KAPPA planchet
   * candidates per coin.
   */
  TALER_EXCHANGE_POST_WITHDRAW_BLINDED_OPTION_WITH_AGE_PROOF

};


/**
 * Value for an option we can set for the POST /withdraw request
 * (low-level, pre-blinded variant).
 */
struct TALER_EXCHANGE_PostWithdrawBlindedOptionValue
{
  /**
   * Type of the option being set.
   */
  enum TALER_EXCHANGE_PostWithdrawBlindedOption option;

  /**
   * Specific option value.
   */
  union
  {
    /**
     * Value if @e option is
     * #TALER_EXCHANGE_POST_WITHDRAW_BLINDED_OPTION_WITH_AGE_PROOF.
     */
    struct
    {
      /**
       * The maximum age to commit to.
       */
      uint8_t max_age;

      /**
       * Array of KAPPA planchet candidates per coin, length matches
       * the @e num_input given to _create().
       */
      const struct TALER_EXCHANGE_WithdrawBlindedAgeRestrictedCoinInput *input;

    } with_age_proof;

  } details;

};


/**
 * Terminate the list of options.
 *
 * @return the terminating object
 */
#define TALER_EXCHANGE_post_withdraw_blinded_option_end_()                         \
        (const struct TALER_EXCHANGE_PostWithdrawBlindedOptionValue)               \
        {                                                                          \
          .option = TALER_EXCHANGE_POST_WITHDRAW_BLINDED_OPTION_END                \
        }

/**
 * Upgrade to an age-proof withdrawal for age-restricted coins.
 *
 * @param age the maximum age to commit to
 * @param inp pointer to array of KAPPA planchet candidates per coin
 * @return representation of the option
 */
#define TALER_EXCHANGE_post_withdraw_blinded_option_with_age_proof(age, inp)          \
        (const struct TALER_EXCHANGE_PostWithdrawBlindedOptionValue)                  \
        {                                                                             \
          .option = TALER_EXCHANGE_POST_WITHDRAW_BLINDED_OPTION_WITH_AGE_PROOF,      \
          .details.with_age_proof.max_age = (age),                                   \
          .details.with_age_proof.input = (inp)                                      \
        }


/**
 * Set the requested options for the operation.
 *
 * If any option fails, other options may or may not be applied.
 *
 * @param pwbh 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_post_withdraw_blinded_set_options_ (
  struct TALER_EXCHANGE_PostWithdrawBlindedHandle *pwbh,
  unsigned int num_options,
  const struct TALER_EXCHANGE_PostWithdrawBlindedOptionValue options[]);


/**
 * Set the requested options for the operation.
 *
 * If any option fails, other options may or may not be applied.
 *
 * @param pwbh the request to set the options for
 * @param ... the list of the options, each created by a
 *            TALER_EXCHANGE_post_withdraw_blinded_option_NAME(VALUE) macro
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
#define TALER_EXCHANGE_post_withdraw_blinded_set_options(pwbh,...)                     \
        TALER_EXCHANGE_post_withdraw_blinded_set_options_ (                            \
          pwbh,                                                                        \
          TALER_EXCHANGE_COMMON_OPTIONS_ARRAY_MAX_SIZE,                                \
          ((const struct TALER_EXCHANGE_PostWithdrawBlindedOptionValue[])              \
           {__VA_ARGS__,                                                               \
            TALER_EXCHANGE_post_withdraw_blinded_option_end_ ()}                       \
          ))


/**
 * Response from a POST /withdraw request (low-level, pre-blinded variant).
 */
struct TALER_EXCHANGE_PostWithdrawBlindedResponse
{
  /**
   * HTTP response data.
   */
  struct TALER_EXCHANGE_HttpResponse hr;

  /**
   * Details about the response
   */
  union
  {
    /**
     * Details if the status is #MHD_HTTP_OK
     */
    struct
    {
      /**
       * Number of signatures returned.
       */
      unsigned int num_sigs;

      /**
       * Array of @e num_sigs blinded denomination signatures, giving each
       * coin its value and validity. The array gives these coins in the same
       * order (and should have the same length) in which the original
       * withdraw request specified the respective denomination keys.
       */
      const struct TALER_BlindedDenominationSignature *blinded_denom_sigs;

      /**
       * The commitment of the withdraw request, needed for the later calls to /recoup
       */
      struct TALER_HashBlindedPlanchetsP planchets_h;

    } ok;

    /**
     * Details if the status is MHD_HTTP_CREATED, i.e. in case of
     * age-restriction.  The response is input to prepare the required
     * follow-up call to /reveal-withdraw.
     */
    struct TALER_EXCHANGE_WithdrawCreated created;

    /**
     * Details if the status is #MHD_HTTP_CONFLICT.
     */
    struct
    {
      /**
       * Details depending on the EC.
       */
      union
      {

        /**
         * Further details if the EC is
         * #TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS.
         */
        struct
        {
          /**
           * Balance of the reserve.
           */
          struct TALER_Amount balance;

          /**
           * Amount that was requested.
           */
          struct TALER_Amount requested_amount;
        } generic_insufficient_funds;

      } details;

    } conflict;

    /**
     * Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
     */
    struct TALER_EXCHANGE_KycNeededRedirect unavailable_for_legal_reasons;

  } details;
};


#ifndef TALER_EXCHANGE_POST_WITHDRAW_BLINDED_RESULT_CLOSURE
/**
 * Type of the closure used by
 * the #TALER_EXCHANGE_PostWithdrawBlindedCallback.
 */
#define TALER_EXCHANGE_POST_WITHDRAW_BLINDED_RESULT_CLOSURE void
#endif /* TALER_EXCHANGE_POST_WITHDRAW_BLINDED_RESULT_CLOSURE */

/**
 * Type of the function that receives the result of a
 * POST /withdraw request (low-level, pre-blinded variant).
 *
 * @param cls closure
 * @param result result returned by the HTTP server
 */
typedef void
(*TALER_EXCHANGE_PostWithdrawBlindedCallback)(
  TALER_EXCHANGE_POST_WITHDRAW_BLINDED_RESULT_CLOSURE *cls,
  const struct TALER_EXCHANGE_PostWithdrawBlindedResponse *result);


/**
 * Start POST /withdraw operation (low-level, pre-blinded variant).
 *
 * @param[in,out] pwbh 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_post_withdraw_blinded_start (
  struct TALER_EXCHANGE_PostWithdrawBlindedHandle *pwbh,
  TALER_EXCHANGE_PostWithdrawBlindedCallback cb,
  TALER_EXCHANGE_POST_WITHDRAW_BLINDED_RESULT_CLOSURE *cb_cls);


/**
 * Cancel POST /withdraw operation (low-level, pre-blinded variant).  This
 * function must not be called by clients after the
 * TALER_EXCHANGE_PostWithdrawBlindedCallback has been invoked (as in those
 * cases it'll be called internally by the implementation already).
 *
 * @param[in] pwbh operation to cancel
 */
void
TALER_EXCHANGE_post_withdraw_blinded_cancel (
  struct TALER_EXCHANGE_PostWithdrawBlindedHandle *pwbh);


#endif /* _TALER_EXCHANGE__POST_WITHDRAW_H */
