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

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

  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file taler-merchant-httpd.h
 * @brief HTTP serving layer mainly intended to communicate with the frontend
 * @author Marcello Stanisci
 */
#ifndef TALER_MERCHANT_HTTPD_H
#define TALER_MERCHANT_HTTPD_H

#include "platform.h"
#include "taler_merchantdb_lib.h"
#include <taler/taler_mhd_lib.h>
#include <gnunet/gnunet_mhd_compat.h>
#include "taler_merchant_bank_lib.h"

/**
 * Shorthand for exit jumps.
 */
#define EXITIF(cond)                                              \
  do {                                                            \
    if (cond) { GNUNET_break (0); goto EXITIF_exit; }             \
  } while (0)


/**
 * Supported wire method.  Kept in a DLL.
 */
struct TMH_WireMethod
{
  /**
   * Next entry in DLL.
   */
  struct TMH_WireMethod *next;

  /**
   * Previous entry in DLL.
   */
  struct TMH_WireMethod *prev;

  /**
   * Which wire method / payment target identifier is @e payto_uri using?
   */
  char *wire_method;

  /**
   * Wire details for this instance
   */
  char *payto_uri;

  /**
   * Salt to use when computing @e h_wire from @e payto_uri.
   */
  struct TALER_WireSaltP wire_salt;

  /**
   * Hash of our wire format details as given in @e payto_uri
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * Base URL of the credit facade.
   */
  char *credit_facade_url;

  /**
   * Authentication data to access the credit facade.
   * May be uninitialized if not provided by the client.
   */
  json_t *credit_facade_credentials;

  /**
   * Is this wire method active (should it be included in new contracts)?
   */
  bool active;

  /**
   * Are we currently in a transaction to delete this account?
   */
  bool deleting;

  /**
   * Are we currently in a transaction to enable this account?
   */
  bool enabling;

};


/**
 * A pending GET /orders request that is in long polling mode.
 */
struct TMH_PendingOrder;


/**
 * Information that defines a merchant "instance". That way, a single
 * backend can account for several merchants, as used to do in donation
 * shops
 */
struct TMH_MerchantInstance
{

  /**
   * Next entry in DLL.
   */
  struct TMH_WireMethod *wm_head;

  /**
   * Previous entry in DLL.
   */
  struct TMH_WireMethod *wm_tail;

  /**
   * Hash of the instance ID, key for the DHT.
   */
  struct GNUNET_HashCode h_instance;

  /**
   * Head of DLL of long-polling GET /orders requests of this instance.
   */
  struct TMH_PendingOrder *po_head;

  /**
   * Tail of DLL of long-polling GET /orders requests of this instance.
   */
  struct TMH_PendingOrder *po_tail;

  /**
   * Database event we are waiting on to be resuming
   * long-polling requests from the @e po_head.
   */
  struct GNUNET_DB_EventHandler *po_eh;

  /**
   * Merchant's private key.
   */
  struct TALER_MerchantPrivateKeyP merchant_priv;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * General settings for an instance.
   */
  struct TALER_MERCHANTDB_InstanceSettings settings;

  /**
   * General settings for an instance.
   */
  struct TALER_MERCHANTDB_InstanceAuthSettings auth;

  /**
   * Reference counter on this structure. Only destroyed if the
   * counter hits zero.
   */
  unsigned int rc;

  /**
   * True if this instance was deleted (but not yet purged).
   */
  bool deleted;

  /**
   * The authentication settings for this instance
   * were changed via the command-line. Do not check
   * against the DB value when updating the auth token.
   */
  bool auth_override;
};


GNUNET_NETWORK_STRUCT_BEGIN


/**
 * Event triggered when an order is paid.
 */
struct TMH_OrderPayEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_ORDER_PAID
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash of the order ID.
   */
  struct GNUNET_HashCode h_order_id;
};


/**
 * Event triggered when a fulfillment URL is
 * bound to a session (as paid).
 */
struct TMH_SessionEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_SESSION_CAPTURED
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash of the fulfillment URL.
   */
  struct GNUNET_HashCode h_fulfillment_url;

  /**
   * Hash of the session ID
   */
  struct GNUNET_HashCode h_session_id;
};


/**
 * Event triggered when an order's refund is increased
 * or obtained by the respective wallet.
 *
 * Extra arguments are the amount (as a string).
 */
struct TMH_OrderRefundEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_ORDER_REFUND or
   * #TALER_DBEVENT_MERCHANT_REFUND_OBTAINED
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash of the order ID.
   */
  struct GNUNET_HashCode h_order_id;
};


/**
 * Event generated when a client picks up a reward.
 */
struct TMH_RewardPickupEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_REWARD_PICKUP.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Reward ID.
   */
  struct TALER_RewardIdentifierP reward_id;

  /**
   * Hash of the instance ID.
   */
  struct GNUNET_HashCode h_instance;

};

/**
 * Possible flags indicating the state of an order.
 */
enum TMH_OrderStateFlags
{
  TMH_OSF_NONE = 0,

  /**
   * Not yet used.
   */
  TMH_OSF_CLAIMED = 1,

  /**
   * Customer paid the order.
   */
  TMH_OSF_PAID = 2,

  /**
   * Merchant granted (possibly partial) refund.
   */
  TMH_OSF_REFUNDED = 4,

  /**
   * Merchant received the payment from the exchange.
   * FIXME: not triggered yet!
   */
  TMH_OSF_WIRED = 8
};


/**
 * Extra information passed for a
 * #TALER_DBEVENT_MERCHANT_ORDERS_CHANGE.
 */
struct TMH_OrderChangeEventDetailsP
{
  /**
   * Order ID, in NBO.
   */
  uint64_t order_serial_id GNUNET_PACKED;

  /**
   * Execution date of the order.
   */
  struct GNUNET_TIME_TimestampNBO execution_date;

  /**
   * See `enum TMH_OrderStateFlags`. In NBO.
   */
  uint32_t order_state GNUNET_PACKED;

};


/**
 * Event triggered when an order's refund is increased
 * or obtained by the respective wallet.
 *
 * Extra arguments are the amount (as a string).
 */
struct TMH_OrderChangeEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_ORDERS_CHANGE.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;
};


GNUNET_NETWORK_STRUCT_END

/**
 * @brief Struct describing an URL and the handler for it.
 *
 * The overall URL is always @e url_prefix, optionally followed by the
 * id_segment, which is optionally followed by the @e url_suffix. It is NOT
 * allowed for the @e url_prefix to be directly followed by the @e url_suffix.
 * A @e url_suffix SHOULD only be used with a @e method of #MHD_HTTP_METHOD_POST.
 */
struct TMH_RequestHandler;

/**
 * This information is stored in the "connection_cls" of MHD for
 * every request that we process.
 * Individual handlers can evaluate its members and
 * are allowed to update @e cc and @e ctx to store and clean up
 * handler-specific data.
 */
struct TMH_HandlerContext;


/**
 * Possible authorization scopes. This is a bit mask.
 */
enum TMH_AuthScope
{
  /**
   * Nothing is authorized.
   */
  TMH_AS_NONE = 0,

  /**
   * Read-only access is OK. Any GET request is
   * automatically OK.
   */
  TMH_AS_READ_ONLY = 1,

  /**
   * /login access to renew the token is OK.
   */
  TMH_AS_REFRESHABLE = 2,

  /**
   * Full access is granted to everything.
   */
  TMH_AS_ALL = 7
};


/**
 * @brief Struct describing an URL and the handler for it.
 *
 * The overall URL is always @e url_prefix, optionally followed by the
 * id_segment, which is optionally followed by the @e url_suffix. It is NOT
 * allowed for the @e url_prefix to be directly followed by the @e url_suffix.
 * A @e url_suffix SHOULD only be used with a @e method of #MHD_HTTP_METHOD_POST.
 */
struct TMH_RequestHandler
{

  /**
   * URL prefix the handler is for, includes the '/',
   * so "/orders", "/templates", "/webhooks" or "/products".  Does *not* include
   * "/private", that is controlled by the array in which
   * the handler is defined.  Must not contain any
   * '/' except for the leading '/'.
   */
  const char *url_prefix;

  /**
   * Required authentication scope for this request.  NONE implies that
   * #TMH_AS_ALL is required unless this is a #MHD_HTTP_METHOD_GET method, in which
   * case #TMH_AS_READ_ONLY is sufficient.
   */
  enum TMH_AuthScope auth_scope;

  /**
   * Does this request include an identifier segment
   * (product_id, reserve_pub, order_id, reward_id, template_id, webhook_id) in the
   * second segment?
   */
  bool have_id_segment;

  /**
   * Does this request handler work without an instance?
   */
  bool skip_instance;

  /**
   * Does this endpoint ONLY apply for the default instance?
   */
  bool default_only;

  /**
   * Does this request handler work with a deleted instance?
   */
  bool allow_deleted_instance;

  /**
   * URL suffix the handler is for, excludes the '/',
   * so "pay" or "claim", not "/pay".
   */
  const char *url_suffix;

  /**
   * HTTP method the handler is for, NULL for "all".
   */
  const char *method;

  /**
   * Mime type to use in reply (hint, can be NULL).
   */
  const char *mime_type;

  /**
   * Raw data for the @e handler (can be NULL).
   */
  const void *data;

  /**
   * Number of bytes in @e data.
   */
  size_t data_size;

  /**
   * Maximum upload size allowed for this handler.
   * 0 for #DEFAULT_MAX_UPLOAD_SIZE.
   */
  size_t max_upload;

  /**
   * Handler to be called for this URL/METHOD combination.
   *
   * @param rh this struct
   * @param connection the MHD connection to handle
   * @param[in,out] hc context with further information about the request
   * @return MHD result code
   */
  MHD_RESULT
  (*handler)(const struct TMH_RequestHandler *rh,
             struct MHD_Connection *connection,
             struct TMH_HandlerContext *hc);

  /**
   * Default response code to use.
   */
  unsigned int response_code;
};


/**
 * Signature of a function used to clean up the context
 * we keep in the "connection_cls" of MHD when handling
 * a request.
 *
 * @param ctx the context to clean up.
 */
typedef void
(*TMH_ContextCleanup)(void *ctx);


/**
 * This information is stored in the "connection_cls" of MHD for
 * every request that we process.
 * Individual handlers can evaluate its members and
 * are allowed to update @e cc and @e ctx to store and clean up
 * handler-specific data.
 */
struct TMH_HandlerContext
{

  /**
   * Function to execute the handler-specific cleanup of the
   * (request-specific) context in @e ctx.
   */
  TMH_ContextCleanup cc;

  /**
   * Client-specific context we keep. Passed to @e cc.
   */
  void *ctx;

  /**
   * Which request handler is handling this request?
   */
  const struct TMH_RequestHandler *rh;

  /**
   * Which instance is handling this request?
   */
  struct TMH_MerchantInstance *instance;

  /**
   * Asynchronous request context id.
   */
  struct GNUNET_AsyncScopeId async_scope_id;

  /**
   * Our original URL, for logging.
   */
  const char *url;

  /**
   * Copy of our original full URL with query parameters.
   */
  char *full_url;

  /**
   * Client-provided authentication token for this
   * request, can be NULL.
   *
   * Used to check for concurrent, conflicting updates of
   * the authentication information in the database.
   */
  const char *auth_token;

  /**
   * Infix part of @a url.
   */
  char *infix;

  /**
   * JSON body that was uploaded, NULL if @e has_body is false.
   */
  json_t *request_body;

  /**
   * Placeholder for #TALER_MHD_parse_post_json() to keep its internal state.
   * Used when we parse the POSTed data.
   */
  void *json_parse_context;

  /**
   * Total size of the upload so far.
   */
  uint64_t total_upload;

  /**
   * Actual authentication scope of this request.
   * Only set for ``/private/`` requests.
   */
  enum TMH_AuthScope auth_scope;

  /**
   * Set to true if this is an #MHD_HTTP_METHOD_POST or #MHD_HTTP_METHOD_PATCH request.
   * (In principle #MHD_HTTP_METHOD_PUT may also belong, but we do not have PUTs
   * in the API today, so we do not test for PUT.)
   */
  bool has_body;
};


/**
 * Information common for suspended requests.
 */
struct TMH_SuspendedConnection
{
  /**
   * Which connection was suspended.
   */
  struct MHD_Connection *con;

  /**
   * At what time does this request expire? If set in the future, we
   * may wait this long for a payment to arrive before responding.
   */
  struct GNUNET_TIME_Absolute long_poll_timeout;

  /**
   * Minimum refund amount to be exceeded (exclusive this value!) for resume.
   */
  struct TALER_Amount refund_expected;

  /**
   * true if we are waiting for a refund.
   */
  bool awaiting_refund;

  /**
   * Whether we're waiting for the refunds to be obtained.
   */
  bool awaiting_refund_obtained;

};


/**
 * Which currency do we use?
 */
extern char *TMH_currency;

/**
 * What is the base URL for this merchant backend?  NULL if it is not
 * configured and is to be determined from HTTP headers (X-Forwarded-Host and
 * X-Forwarded-Port and X-Forwarded-Prefix) of the reverse proxy.
 */
extern char *TMH_base_url;

/**
 * Length of the TMH_cspecs array.
 */
extern unsigned int TMH_num_cspecs;

/**
 * Rendering specs for currencies.
 */
extern struct TALER_CurrencySpecification *TMH_cspecs;

/**
 * Inform the auditor for all deposit confirmations (global option)
 */
extern int TMH_force_audit;

/**
 * Context for all CURL operations (useful to the event loop)
 */
extern struct GNUNET_CURL_Context *TMH_curl_ctx;

/**
 * Handle to the database backend.
 */
extern struct TALER_MERCHANTDB_Plugin *TMH_db;

/**
 * Hashmap pointing at merchant instances by 'id'. An 'id' is
 * just a string that identifies a merchant instance. When a frontend
 * needs to specify an instance to the backend, it does so by 'id'
 */
extern struct GNUNET_CONTAINER_MultiHashMap *TMH_by_id_map;

/**
 * How long do we need to keep information on paid contracts on file for tax
 * or other legal reasons?  Used to block deletions for younger transaction
 * data.
 */
extern struct GNUNET_TIME_Relative TMH_legal_expiration;

/**
 * Initial authorization token.
 */
extern char *TMH_default_auth;


/**
 * Callback that frees an instances removing
 * it from the global hashmap.
 *
 * @param cls closure, pass NULL
 * @param key current key (ignored)
 * @param value a `struct TMH_MerchantInstance`
 * @return #GNUNET_YES (always)
 */
enum GNUNET_GenericReturnValue
TMH_instance_free_cb (void *cls,
                      const struct GNUNET_HashCode *key,
                      void *value);


/**
 * Add instance definition to our active set of instances.
 *
 * @param[in,out] mi merchant instance details to define
 * @return #GNUNET_OK on success, #GNUNET_NO if the same ID is in use already
 */
enum GNUNET_GenericReturnValue
TMH_add_instance (struct TMH_MerchantInstance *mi);


/**
 * Decrement reference counter of @a mi, and free if it hits zero.
 *
 * @param[in,out] mi merchant instance to update and possibly free
 */
void
TMH_instance_decref (struct TMH_MerchantInstance *mi);


/**
 * Free memory allocated by @a wm.
 *
 * @param[in] wm wire method to free
 */
void
TMH_wire_method_free (struct TMH_WireMethod *wm);


/**
 * Lookup a merchant instance by its instance ID.
 *
 * @param instance_id identifier of the instance to resolve
 * @return NULL if that instance is unknown to us
 */
struct TMH_MerchantInstance *
TMH_lookup_instance (const char *instance_id);


/**
 * A transaction modified an instance setting
 * (or created/deleted/purged one). Notify all
 * backends about the change.
 *
 * @param id ID of the instance that changed
 */
void
TMH_reload_instances (const char *id);


/**
 * Check that @a token hashes to @a hash under @a salt for
 * merchant instance authentication.
 *
 * @param token the token to check
 * @param salt the salt to use when hashing
 * @param hash the hash to check against
 * @return #GNUNET_OK if the @a token matches
 */
enum GNUNET_GenericReturnValue
TMH_check_auth (const char *token,
                struct TALER_MerchantAuthenticationSaltP *salt,
                struct TALER_MerchantAuthenticationHashP *hash);


/**
 * Compute a @a hash from @a token hashes for
 * merchant instance authentication.
 *
 * @param token the token to check
 * @param[out] salt set to a fresh random salt
 * @param[out] hash set to the hash of @a token under @a salt
 */
void
TMH_compute_auth (const char *token,
                  struct TALER_MerchantAuthenticationSaltP *salt,
                  struct TALER_MerchantAuthenticationHashP *hash);


#endif