/*
  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/get-private-kyc.h
 * @brief C interface for the GET /private/kyc (and /management/instances/$INSTANCE/kyc) endpoint
 * @author Christian Grothoff
 */
#ifndef _TALER_MERCHANT__GET_PRIVATE_KYC_H
#define _TALER_MERCHANT__GET_PRIVATE_KYC_H

#include <taler/merchant/common.h>


/**
 * Possible options we can set for the GET /private/kyc request.
 */
enum TALER_MERCHANT_GetPrivateKycOption
{
  /**
   * End of list of options.
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_END = 0,

  /**
   * Hash of the wire account to check, or NULL for all.
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_H_WIRE,

  /**
   * URL of the exchange to check with, or NULL for any.
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_EXCHANGE_URL,

  /**
   * Long-poll target (what status to wait for).
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LPT,

  /**
   * Long polling timeout.
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_TIMEOUT,

  /**
   * Instance ID for management mode (GET /management/instances/$INSTANCE/kyc).
   * If not set, uses the private endpoint (GET /private/kyc).
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_INSTANCE_ID,

  /**
   * Long-poll status filter: only return when some account reaches
   * this status.  String value (since v25).
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_STATUS,

  /**
   * Long-poll negated status filter: only return when some account
   * no longer matches this status.  String value (since v25).
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_NOT_STATUS,

  /**
   * Long-poll ETag to suppress responses that have not changed.
   * ShortHashCode value (since v25).
   */
  TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_NOT_ETAG

};


/**
 * Value for an option for the GET /private/kyc request.
 */
struct TALER_MERCHANT_GetPrivateKycOptionValue
{

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

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

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_H_WIRE.
     */
    const struct TALER_MerchantWireHashP *h_wire;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_EXCHANGE_URL.
     */
    const char *exchange_url;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LPT.
     */
    enum TALER_EXCHANGE_KycLongPollTarget lpt;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_TIMEOUT.
     */
    struct GNUNET_TIME_Relative timeout;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_INSTANCE_ID.
     * If set, the management endpoint
     * /management/instances/$INSTANCE/kyc is used instead of
     * /private/kyc.
     */
    const char *instance_id;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_STATUS.
     */
    const char *lp_status;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_NOT_STATUS.
     */
    const char *lp_not_status;

    /**
     * Value if @e option is
     * #TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_NOT_ETAG.
     */
    const struct GNUNET_ShortHashCode *lp_not_etag;

  } details;

};


/**
 * Handle for a GET /private/kyc (or /management/instances/$INSTANCE/kyc) request.
 */
struct TALER_MERCHANT_GetPrivateKycHandle;


/**
 * Set up GET /private/kyc operation.
 * Note that you must explicitly start the operation after
 * possibly setting options.  By default, uses the /private/kyc
 * endpoint; set the INSTANCE_ID option to use the management
 * endpoint instead.
 *
 * @param ctx the context
 * @param url base URL of the merchant backend
 * @return handle to operation
 */
struct TALER_MERCHANT_GetPrivateKycHandle *
TALER_MERCHANT_get_private_kyc_create (
  struct GNUNET_CURL_Context *ctx,
  const char *url);


/**
 * Terminate the list of the options.
 *
 * @return the terminating object of struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_end_()                \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)      \
        {                                                            \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_END       \
        }

/**
 * Set hash of the wire account to check.
 *
 * @param h pointer to the wire hash to filter by
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_h_wire(h)              \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)       \
        {                                                             \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_H_WIRE,    \
          .details.h_wire = (h)                                       \
        }

/**
 * Set exchange URL to check with.
 *
 * @param u exchange URL to filter by
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_exchange_url(u)              \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)             \
        {                                                                   \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_EXCHANGE_URL,    \
          .details.exchange_url = (u)                                       \
        }

/**
 * Set long-poll target.
 *
 * @param t long-poll target to wait for
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_lpt(t)              \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)    \
        {                                                          \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LPT,    \
          .details.lpt = (t)                                       \
        }

/**
 * Set long polling timeout.
 *
 * @param t timeout to use
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_timeout(t)              \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)        \
        {                                                              \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_TIMEOUT,    \
          .details.timeout = (t)                                       \
        }

/**
 * Set instance ID for management mode.  When set, the request uses
 * the /management/instances/$INSTANCE/kyc endpoint instead of
 * /private/kyc.
 *
 * @param id instance identifier
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_instance_id(id)              \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)             \
        {                                                                   \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_INSTANCE_ID,     \
          .details.instance_id = (id)                                       \
        }

/**
 * Set long-poll status filter.
 *
 * @param s status string to wait for
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_lp_status(s)                  \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)              \
        {                                                                    \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_STATUS,        \
          .details.lp_status = (s)                                           \
        }

/**
 * Set long-poll negated status filter.
 *
 * @param s status string to negate
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_lp_not_status(s)              \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)              \
        {                                                                    \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_NOT_STATUS,    \
          .details.lp_not_status = (s)                                       \
        }

/**
 * Set long-poll ETag to suppress unchanged responses.
 *
 * @param e pointer to the short hash code ETag
 * @return representation of the option as a struct TALER_MERCHANT_GetPrivateKycOptionValue
 */
#define TALER_MERCHANT_get_private_kyc_option_lp_not_etag(e)                \
        (const struct TALER_MERCHANT_GetPrivateKycOptionValue)              \
        {                                                                    \
          .option = TALER_MERCHANT_GET_PRIVATE_KYC_OPTION_LP_NOT_ETAG,      \
          .details.lp_not_etag = (e)                                         \
        }


/**
 * Set the requested options for the operation.
 *
 * If any option fail other options may be or may be not applied.
 *
 * @param kyc 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_get_private_kyc_set_options_ (
  struct TALER_MERCHANT_GetPrivateKycHandle *kyc,
  unsigned int num_options,
  const struct TALER_MERCHANT_GetPrivateKycOptionValue *options);


/**
 * Set the requested options for the operation.
 *
 * If any option fail other options may be or may be not applied.
 *
 * It should be used with helpers that create required options, for example:
 *
 * TALER_MERCHANT_get_private_kyc_set_options (
 *   kyc,
 *   TALER_MERCHANT_get_private_kyc_option_exchange_url (
 *     "https://exchange.example.com/"),
 *   TALER_MERCHANT_get_private_kyc_option_timeout (
 *     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)));
 *
 * @param kyc the request to set the options for
 * @param ... the list of the options, each option must be created
 *            by helpers TALER_MERCHANT_get_private_kyc_option_NAME(VALUE)
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
#define TALER_MERCHANT_get_private_kyc_set_options(kyc,...)                \
        TALER_MERCHANT_get_private_kyc_set_options_ (                       \
          kyc,                                                               \
          TALER_MERCHANT_COMMON_OPTIONS_ARRAY_MAX_SIZE,                     \
          ((const struct TALER_MERCHANT_GetPrivateKycOptionValue[])         \
           {__VA_ARGS__, TALER_MERCHANT_get_private_kyc_option_end_ () }    \
          ))


/**
 * Information about KYC actions the merchant still must perform.
 */
struct TALER_MERCHANT_GetPrivateKycRedirectDetail
{

  /**
   * Access token the user needs to start a KYC process,
   * all zero if a KYC auth transfer must be made first.
   */
  struct TALER_AccountAccessTokenP access_token;

  /**
   * Base URL of the exchange this is about.
   */
  const char *exchange_url;

  /**
   * Our bank wire account this is about.
   */
  struct TALER_FullPayto payto_uri;

  /**
   * Array of length @e limits_length with (exposed) limits that apply to the
   * account.
   */
  const struct TALER_EXCHANGE_AccountLimit *limits;

  /**
   * Array of payto://-URIs with instructions for wire
   * transfers to perform a KYC auth wire transfer for
   * the given account. Needed if @e access_token is zero
   * and @e limits are to be passed.
   */
  struct TALER_FullPayto *payto_kycauths;

  /**
   * Length of the @e limits array.
   */
  unsigned int limits_length;

  /**
   * Length of the @e payto_kycauths array.
   */
  unsigned int pkycauth_length;

  /**
   * HTTP status code returned by the exchange when we asked for
   * information about the KYC status.
   * 0 if there was no response at all.
   */
  unsigned int exchange_http_status;

  /**
   * Error code indicating errors the exchange
   * returned, or #TALER_EC_NONE for none.
   */
  enum TALER_ErrorCode exchange_code;

  /**
   * Set to true if @e access_token was not given.
   */
  bool no_access_token;

  /**
   * Hash of the wire account this entry is about.
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * KYC status string, or NULL if not provided.
   */
  const char *status;

  /**
   * Currency used by the exchange, or NULL if not provided.
   */
  const char *exchange_currency;

  /**
   * Set to true if the merchant backend could not
   * get the exchanges ``/keys`` and thus could not
   * determine default limits or determine an
   * @e auth_conflict.
   */
  bool no_keys;

  /**
   * Set to true if the given account cannot do KYC at the given exchange
   * because no wire method exists that could be used to do the KYC auth wire
   * transfer.
   */
  bool auth_conflict;

};


/**
 * Response details for a KYC status request.
 */
struct TALER_MERCHANT_GetPrivateKycResponse
{

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

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

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

      /**
       * Number of KYC redirect details in @a kycs.
       */
      unsigned int kycs_length;

      /**
       * Array of KYC redirect details for accounts requiring KYC.
       */
      const struct TALER_MERCHANT_GetPrivateKycRedirectDetail *kycs;

    } ok;

  } details;

};


#ifndef TALER_MERCHANT_GET_PRIVATE_KYC_RESULT_CLOSURE
/**
 * Type of the closure used by
 * the #TALER_MERCHANT_GetPrivateKycCallback.
 */
#define TALER_MERCHANT_GET_PRIVATE_KYC_RESULT_CLOSURE void
#endif /* TALER_MERCHANT_GET_PRIVATE_KYC_RESULT_CLOSURE */

/**
 * Callback for a KYC status request.
 *
 * @param cls closure
 * @param kr response details
 */
typedef void
(*TALER_MERCHANT_GetPrivateKycCallback)(
  TALER_MERCHANT_GET_PRIVATE_KYC_RESULT_CLOSURE *cls,
  const struct TALER_MERCHANT_GetPrivateKycResponse *kr);


/**
 * Start GET /private/kyc (or /management/instances/$INSTANCE/kyc) operation.
 *
 * @param[in,out] kyc 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_get_private_kyc_start (
  struct TALER_MERCHANT_GetPrivateKycHandle *kyc,
  TALER_MERCHANT_GetPrivateKycCallback cb,
  TALER_MERCHANT_GET_PRIVATE_KYC_RESULT_CLOSURE *cb_cls);


/**
 * Cancel GET /private/kyc operation.  This function must not be
 * called by clients after the TALER_MERCHANT_GetPrivateKycCallback
 * has been invoked (as in those cases it'll be called internally by
 * the implementation already).
 *
 * @param[in] kyc operation to cancel
 */
void
TALER_MERCHANT_get_private_kyc_cancel (
  struct TALER_MERCHANT_GetPrivateKycHandle *kyc);


#endif /* _TALER_MERCHANT__GET_PRIVATE_KYC_H */
