/*
  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 Lesser General Public License as published by the Free Software
  Foundation; either version 2.1, 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 Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License along with
  TALER; see the file COPYING.LGPL.  If not, see
  <http://www.gnu.org/licenses/>
*/
/**
 * @file src/include/taler/merchant/post-orders-ORDER_ID-pay.h
 * @brief C interface for the POST /orders/$ORDER_ID/pay endpoint
 * @author Christian Grothoff
 * @author Marcello Stanisci
 */
#ifndef _TALER_MERCHANT__POST_ORDERS_ORDER_ID_PAY_H
#define _TALER_MERCHANT__POST_ORDERS_ORDER_ID_PAY_H

#include <taler/merchant/common.h>

/**
 * Forward-declaration here to keep the API stable even if
 * the Donau header is not available.
 */
struct DONAU_BlindedUniqueDonorIdentifierKeyPair;

/**
 * One coin used to pay (frontend / external wallet mode).
 */
struct TALER_MERCHANT_PostOrdersPayPaidCoin
{

  /**
   * Denomination public key.
   */
  struct TALER_DenominationPublicKey denom_pub;

  /**
   * Hash of the denomination public key.
   */
  struct TALER_DenominationHashP denom_pub_hash;

  /**
   * Denomination signature over the coin.
   */
  struct TALER_DenominationSignature denom_sig;

  /**
   * Face value of the denomination.
   */
  struct TALER_Amount denom_value;

  /**
   * Public key of the coin.
   */
  struct TALER_CoinSpendPublicKeyP coin_pub;

  /**
   * Signature by the coin authorizing the deposit.
   */
  struct TALER_CoinSpendSignatureP coin_sig;

  /**
   * Hash of the age commitment for this coin.
   */
  struct TALER_AgeCommitmentHashP h_age_commitment;

  /**
   * Set to true if this coin has an age commitment.
   */
  bool has_age_commitment;

  /**
   * Total amount contributed including deposit fee.
   */
  struct TALER_Amount amount_with_fee;

  /**
   * Amount contributed without the deposit fee.
   */
  struct TALER_Amount amount_without_fee;

  /**
   * Deposit fee for this coin.
   */
  struct TALER_Amount deposit_fee;

  /**
   * Base URL of the exchange this coin was issued by.
   */
  char *exchange_url;

};


/**
 * One coin used to pay (wallet-internal mode, private key available).
 */
struct TALER_MERCHANT_PostOrdersPayCoin
{

  /**
   * Denomination public key.
   */
  struct TALER_DenominationPublicKey denom_pub;

  /**
   * Denomination signature over the coin.
   */
  struct TALER_DenominationSignature denom_sig;

  /**
   * Face value of the denomination.
   */
  struct TALER_Amount denom_value;

  /**
   * Private key of the coin (to sign the deposit).
   */
  struct TALER_CoinSpendPrivateKeyP coin_priv;

  /**
   * Hash of the age commitment for this coin, or
   * all zeros if none.
   */
  struct TALER_AgeCommitmentHashP h_age_commitment;

  /**
   * Total amount contributed including deposit fee.
   */
  struct TALER_Amount amount_with_fee;

  /**
   * Amount contributed without the deposit fee.
   */
  struct TALER_Amount amount_without_fee;

  /**
   * URL of the exchange that issued @e coin_priv.
   */
  char *exchange_url;

};


/**
 * Token to use for payment (public form, already obtained).
 */
struct TALER_MERCHANT_PostOrdersPayUsedToken
{

  /**
   * Signature on TALER_TokenUseRequestPS made with the token use private key.
   */
  struct TALER_TokenUseSignatureP token_sig;

  /**
   * Public key of the token.
   */
  struct TALER_TokenUsePublicKeyP token_pub;

  /**
   * Unblinded signature made by the token issue public key of the merchant.
   */
  struct TALER_TokenIssueSignature ub_sig;

  /**
   * Token issue public key associated with this token.
   */
  struct TALER_TokenIssuePublicKey issue_pub;

};


/**
 * Information we need from the wallet to use a token for an order.
 */
struct TALER_MERCHANT_PostOrdersPayUseToken
{

  /**
   * Private key of the token (to sign the use authorization).
   */
  struct TALER_TokenUsePrivateKeyP token_priv;

  /**
   * Unblinded signature made by the token issue public key of the merchant.
   */
  struct TALER_TokenIssueSignature ub_sig;

  /**
   * Token issue public key associated with this token.
   */
  struct TALER_TokenIssuePublicKey issue_pub;

};


/**
 * Output token: used both as input to pay (envelope to be signed)
 * and as output in the pay response (blind signature received).
 */
struct TALER_MERCHANT_PostOrdersPayOutputToken
{

  /**
   * Blinded token envelope to be signed by the issuer (input to pay).
   */
  struct TALER_TokenEnvelope envelope;

  /**
   * Blinded token issue signature received from the issuer (output of pay).
   */
  struct TALER_BlindedTokenIssueSignature blinded_sig;

};


/**
 * Possible options for the POST /orders/$ORDER_ID/pay request.
 */
enum TALER_MERCHANT_PostOrdersPayOption
{
  /**
   * End of list of options.
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_END = 0,

  /**
   * Session identifier for session-bound payments.
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_SESSION_ID,

  /**
   * Wallet-specific data (JSON).
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_WALLET_DATA,

  /**
   * Used tokens (public form, for frontend mode).
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USED_TOKENS,

  /**
   * Use tokens (private form, for wallet mode).
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USE_TOKENS,

  /**
   * Output tokens (for wallet mode).
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS,

  /**
   * Output tokens as JSON array (for frontend mode).
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON,

  /**
   * Output donation receipts.
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU,

  /**
   * Payment choice index (wallet mode).
   */
  TALER_MERCHANT_POST_ORDERS_PAY_OPTION_CHOICE_INDEX

};


/**
 * Value for an option for the POST /orders/$ORDER_ID/pay request.
 */
struct TALER_MERCHANT_PostOrdersPayOptionValue
{

  /**
   * Type of the option being set.
   */
  enum TALER_MERCHANT_PostOrdersPayOption option;

  /**
   * Specific option value.
   */
  union
  {

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_SESSION_ID.
     */
    const char *session_id;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_WALLET_DATA.
     */
    const json_t *wallet_data;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USED_TOKENS.
     */
    struct
    {
      /**
       * Length of @e tokens array
       */
      unsigned int num;
      const struct TALER_MERCHANT_PostOrdersPayUsedToken *tokens;
    } used_tokens;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USE_TOKENS.
     */
    struct
    {
      /**
       * Length of @e tokens array
       */
      unsigned int num;
      const struct TALER_MERCHANT_PostOrdersPayUseToken *tokens;
    } use_tokens;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS.
     */
    struct
    {
      /**
       * Length of @e tokens array
       */
      unsigned int num;
      const struct TALER_MERCHANT_PostOrdersPayOutputToken *tokens;
    } output_tokens;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON.
     */
    json_t *output_tokens_json;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU.
     */
    struct
    {
      /**
       * Base URL of the donau.
       */
      const char *donau_base_url;

      /**
       * Array of blinded dontation receipts.
       */
      const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps;

      /**
       * Length of @e bkps array
       */
      size_t num_bkps;

      /**
       * Year for which the donation receipts are issued.
       */
      uint64_t year;
    } output_donau;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_POST_ORDERS_PAY_OPTION_CHOICE_INDEX.
     */
    int choice_index;

  } details;

};


/**
 * Handle for a POST /orders/$ORDER_ID/pay request.
 */
struct TALER_MERCHANT_PostOrdersPayHandle;


/**
 * Response details for a POST /orders/$ORDER_ID/pay request.
 */
struct TALER_MERCHANT_PostOrdersPayResponse
{

  /**
   * HTTP response details.
   */
  struct TALER_MERCHANT_HttpResponse hr;

  /**
   * Details depending on the HTTP status code.
   */
  union
  {

    /**
     * Details on #MHD_HTTP_OK.
     */
    struct
    {

      /**
       * Merchant signature confirming the payment.
       */
      struct TALER_MerchantSignatureP merchant_sig;

      /**
       * POS confirmation string, or NULL if not applicable.
       */
      const char *pos_confirmation;

      /**
       * Number of output tokens in @a tokens.
       */
      unsigned int num_tokens;

      /**
       * Array of output tokens issued upon payment.
       */
      struct TALER_MERCHANT_PostOrdersPayOutputToken *tokens;

    } ok;

    /**
     * Details on #MHD_HTTP_CONFLICT.
     * Set when a coin was already spent (insufficient funds) or
     * the order was already fully paid.
     */
    struct
    {

      /**
       * Base URL of the exchange that reported the conflict,
       * or NULL if not applicable.
       */
      const char *exchange_url;

      /**
       * Taler error code from the exchange, if available.
       */
      enum TALER_ErrorCode exchange_ec;

      /**
       * HTTP status code returned by the exchange, if available.
       */
      unsigned int exchange_http_status;

    } conflict;

    /**
     * Details on #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
     */
    struct
    {

      /**
       * Number of exchange URLs in @a exchanges.
       */
      unsigned int num_exchanges;

      /**
       * Array of exchange URLs that refused the payment for legal reasons.
       */
      const char **exchanges;

    } unavailable_for_legal_reasons;

    /**
     * Details on #MHD_HTTP_BAD_GATEWAY.
     * The merchant's interaction with the exchange failed.
     */
    struct
    {

      /**
       * Base URL of the exchange that returned an error,
       * or NULL if not available.
       */
      const char *exchange_url;

      /**
       * Taler error code from the exchange, if available.
       */
      enum TALER_ErrorCode exchange_ec;

      /**
       * HTTP status code returned by the exchange, if available.
       */
      unsigned int exchange_http_status;

    } bad_gateway;

  } details;

};


/**
 * Terminate the list of the options.
 *
 * @return the terminating object
 */
#define TALER_MERCHANT_post_orders_pay_option_end_()                \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_END       \
        }

/**
 * Set session identifier.
 *
 * @param s session ID
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_session_id(s)         \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_SESSION_ID, \
          .details.session_id = (s)                                  \
        }

/**
 * Set wallet-specific data.
 *
 * @param w wallet data JSON object
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_wallet_data(w)        \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_WALLET_DATA, \
          .details.wallet_data = (w)                                 \
        }

/**
 * Set used tokens (public form, for frontend mode).
 *
 * @param n number of tokens
 * @param t array of used tokens
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_used_tokens(n,t)      \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USED_TOKENS, \
          .details.used_tokens = { .num = (n), .tokens = (t) }      \
        }

/**
 * Set use tokens (private form, for wallet mode).
 *
 * @param n number of tokens
 * @param t array of use tokens
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_use_tokens(n,t)       \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USE_TOKENS, \
          .details.use_tokens = { .num = (n), .tokens = (t) }       \
        }

/**
 * Set output tokens (for wallet mode).
 *
 * @param n number of output tokens
 * @param t array of output tokens
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_output_tokens(n,t)    \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS, \
          .details.output_tokens = { .num = (n), .tokens = (t) }    \
        }

/**
 * Set output tokens as JSON array (for frontend mode).
 *
 * @param j JSON array describing desired output tokens
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_output_tokens_json(j) \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON, \
          .details.output_tokens_json = (j)                          \
        }


/**
 * Set blinded donation receipts as output.
 *
 * @param u base URL of the selected Donau
 * @param y year for which receipts are requested
 * @param l length of the @a bkps array
 * @param a array of blinded donation receipts
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_output_donau(u,y,l,a)     \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)          \
        {                                                               \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU, \
          .details.output_donau.donau_base_url = (u),                   \
          .details.output_donau.bkps = (a),                             \
          .details.output_donau.num_bkps = (l),                         \
          .details.output_donau.year = (y)                              \
        }

/**
 * Set payment choice index (wallet mode).
 * Use -1 to indicate no choice (the default).
 *
 * @param i choice index
 * @return representation of the option
 */
#define TALER_MERCHANT_post_orders_pay_option_choice_index(i)              \
        (const struct TALER_MERCHANT_PostOrdersPayOptionValue)             \
        {                                                                   \
          .option = TALER_MERCHANT_POST_ORDERS_PAY_OPTION_CHOICE_INDEX,    \
          .details.choice_index = (i)                                       \
        }


/**
 * Set the requested options for the operation.
 *
 * @param poph 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_MERCHANT_post_orders_pay_set_options_ (
  struct TALER_MERCHANT_PostOrdersPayHandle *poph,
  unsigned int num_options,
  const struct TALER_MERCHANT_PostOrdersPayOptionValue *options);


/**
 * Set the requested options for the operation.
 *
 * @param poph the request to set the options for
 * @param ... the list of the options
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
#define TALER_MERCHANT_post_orders_pay_set_options(poph,...)                \
        TALER_MERCHANT_post_orders_pay_set_options_ (                       \
          poph,                                                              \
          TALER_MERCHANT_COMMON_OPTIONS_ARRAY_MAX_SIZE,                     \
          ((const struct TALER_MERCHANT_PostOrdersPayOptionValue[])          \
           {__VA_ARGS__, TALER_MERCHANT_post_orders_pay_option_end_ () }    \
          ))


/**
 * Set up POST /orders/$ORDER_ID/pay operation in frontend mode
 * (coins already signed by the wallet).
 * Note that you must explicitly start the operation after
 * possibly setting options.
 *
 * @param ctx the context
 * @param url base URL of the merchant backend
 * @param order_id identifier of the order to pay
 * @param num_coins number of coins in @a coins
 * @param coins array of coins to pay with (already signed)
 * @return handle to operation
 */
struct TALER_MERCHANT_PostOrdersPayHandle *
TALER_MERCHANT_post_orders_pay_frontend_create (
  struct GNUNET_CURL_Context *ctx,
  const char *url,
  const char *order_id,
  unsigned int num_coins,
  const struct TALER_MERCHANT_PostOrdersPayPaidCoin coins[static num_coins]);


/**
 * Set up POST /orders/$ORDER_ID/pay operation in wallet-internal mode
 * (signing done internally).
 * Note that you must explicitly start the operation after
 * possibly setting options.
 *
 * @param ctx the context
 * @param url base URL of the merchant backend
 * @param order_id identifier of the order to pay
 * @param h_contract_terms hash of the contract terms
 * @param amount total payment amount
 * @param max_fee maximum acceptable fee
 * @param merchant_pub merchant public key
 * @param merchant_sig merchant signature
 * @param timestamp contract timestamp
 * @param refund_deadline refund deadline
 * @param pay_deadline payment deadline
 * @param h_wire hash of the merchant wire details
 * @param num_coins number of coins in @a coins
 * @param coins array of coins with private keys
 * @return handle to operation
 */
struct TALER_MERCHANT_PostOrdersPayHandle *
TALER_MERCHANT_post_orders_pay_create (
  struct GNUNET_CURL_Context *ctx,
  const char *url,
  const char *order_id,
  const struct TALER_PrivateContractHashP *h_contract_terms,
  const struct TALER_Amount *amount,
  const struct TALER_Amount *max_fee,
  const struct TALER_MerchantPublicKeyP *merchant_pub,
  const struct TALER_MerchantSignatureP *merchant_sig,
  struct GNUNET_TIME_Timestamp timestamp,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  const struct TALER_MerchantWireHashP *h_wire,
  unsigned int num_coins,
  const struct TALER_MERCHANT_PostOrdersPayCoin coins[static num_coins]);


#ifndef TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE
/**
 * Type of the closure used by
 * the #TALER_MERCHANT_PostOrdersPayCallback.
 */
#define TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE void
#endif /* TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE */

/**
 * Callback for a POST /orders/$ORDER_ID/pay request.
 *
 * @param cls closure
 * @param opr response details
 */
typedef void
(*TALER_MERCHANT_PostOrdersPayCallback)(
  TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cls,
  const struct TALER_MERCHANT_PostOrdersPayResponse *opr);


/**
 * Start POST /orders/$ORDER_ID/pay operation.
 *
 * @param[in,out] poph operation to start
 * @param cb function to call with the merchant's result
 * @param cb_cls closure for @a cb
 * @return status code, #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TALER_MERCHANT_post_orders_pay_start (
  struct TALER_MERCHANT_PostOrdersPayHandle *poph,
  TALER_MERCHANT_PostOrdersPayCallback cb,
  TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls);


/**
 * Cancel POST /orders/$ORDER_ID/pay operation.  This function must not be
 * called by clients after the TALER_MERCHANT_PostOrdersPayCallback has
 * been invoked (as in those cases it'll be called internally by the
 * implementation already).
 *
 * @param[in] poph operation to cancel
 */
void
TALER_MERCHANT_post_orders_pay_cancel (
  struct TALER_MERCHANT_PostOrdersPayHandle *poph);


#endif /* _TALER_MERCHANT__POST_ORDERS_ORDER_ID_PAY_H */
