/*
  This file is part of GNU Taler
  Copyright (C) 2024, 2025 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 src/include/taler/taler_merchant_util.h
 * @brief Interface for common utility functions
 * @author Christian Grothoff
 */
#ifndef TALER_MERCHANT_UTIL_H
#define TALER_MERCHANT_UTIL_H

#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>

#include <stdint.h>
#include <taler/taler_util.h>
#include <jansson.h>

/**
 * Fixed-point base for inventory quantities (powers of 10).
 * Six decimal digits are supported to match the maximum unit precision.
 */
#define TALER_MERCHANT_UNIT_FRAC_BASE 1000000U
#define TALER_MERCHANT_UNIT_FRAC_MAX_DIGITS 6U

/**
 * Return default project data used by Taler merchant.
 */
const struct GNUNET_OS_ProjectData *
TALER_MERCHANT_project_data (void);


/**
 * Kind of fixed-decimal value the helpers operate on.
 * Primarily distinguishes how special sentinel values (such as "-1"
 * meaning infinity for stock) must be encoded.
 */
enum TALER_MERCHANT_ValueKind
{
  TALER_MERCHANT_VK_QUANTITY,  /* -1 is illegal                    */
  TALER_MERCHANT_VK_STOCK      /* -1 means "infinity"              */
};


/**
 * Parse decimal quantity expressed as string for request handling.
 *
 * @param value string to parse
 * @param[out] integer_part result integer component
 * @param[out] fractional_part result fractional component (0..TALER_MERCHANT_UNIT_FRAC_BASE-1)
 * @return #GNUNET_OK on success, #GNUNET_SYSERR on validation failure
 */
enum GNUNET_GenericReturnValue
TALER_MERCHANT_vk_parse_fractional_string (
  const char *value,
  int64_t *integer_part,
  uint32_t *fractional_part);


/**
 * Extract a fixed-decimal number that may be supplied either
 *   - as pure integer  (e.g. "total_stock"), or
 *   - as decimal text (e.g. "unit_total_stock").
 *
 * Rules:
 *  - If both forms are missing          -> error.
 *  - If both are present                -> they must match and the decimal must have no fraction.
 *  - For kind == TALER_MERCHANT_VK_STOCK the integer value -1 represents infinity.
 *
 * @param kind             See #TALER_MERCHANT_ValueKind
 * @param allow_fractional False: any fractional part is rejected
 * @param int_missing      True if client omitted the integer field
 * @param int_raw          Raw integer (undefined if @a int_missing is true)
 * @param str_missing      True if client omitted the string field
 * @param str_raw          Raw UTF-8 string (undefined if @a str_missing is true)
 * @param[out] int_out     Canonicalised integer part
 * @param[out] frac_out    Canonicalised fractional part
 * @param[out] error_param Set to offending field name on failure
 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
 */
enum GNUNET_GenericReturnValue
TALER_MERCHANT_vk_process_quantity_inputs (
  enum TALER_MERCHANT_ValueKind kind,
  bool allow_fractional,
  bool int_missing,
  int64_t int_raw,
  bool str_missing,
  const char *str_raw,
  uint64_t *int_out,
  uint32_t *frac_out,
  const char **error_param);


/**
 * Format a fixed-decimal pair into canonical string representation.
 * Recognises INT64_MAX / INT32_MAX as the "-1" sentinel used for
 * infinite stock if @a kind equals #TALER_MERCHANT_VK_STOCK.
 *
 * @param kind specifies whether sentinel values are permitted
 * @param integer integer portion
 * @param fractional fractional portion (0..TALER_MERCHANT_UNIT_FRAC_BASE-1 or sentinel)
 * @param buffer output buffer
 * @param buffer_length length of @a buffer
 */
void
TALER_MERCHANT_vk_format_fractional_string (
  enum TALER_MERCHANT_ValueKind kind,
  uint64_t integer,
  uint32_t fractional,
  size_t buffer_length,
  char buffer[static buffer_length]);


/**
 * Check if @a image_data_url is a valid image
 * data URL. Does not validate the actual payload,
 * only the syntax and that it properly claims to
 * be an image.
 *
 * FIXME: use in TALER_MERCHANT_parse_product!
 *
 * @param image_data_url string to check
 * @return true if @a image_data_url is a data
 *         URL with an "image/" mime-type
 */
bool
TALER_MERCHANT_image_data_url_valid (const char *image_data_url);


/**
 * Check if @a email is a valid email address.
 *
 * FIXME: move to libgnunetutil?
 *
 * @param email string to check
 * @return true if @a email is a valid e-mail address
 */
bool
TALER_MERCHANT_email_valid (const char *email);


/**
 * Check if @a email is a valid international phone number
 * with "+CC" prefix.
 *
 * @param phone phone number to check
 * @param allow_letters to allow "A-Z" letters representing digits
 * @return normalized phone number if @a phone is valid,
 *   NULL if @a phone is not a phone number
 */
char *
TALER_MERCHANT_phone_validate_normalize (const char *phone,
                                         bool allow_letters);


/**
 * Channel used to transmit MFA authorization request.
 */
enum TALER_MERCHANT_MFA_Channel
{
  /**
   * No MFA channel.
   */
  TALER_MERCHANT_MFA_CHANNEL_NONE = 0,

  /**
   * SMS ("sms")
   */
  TALER_MERCHANT_MFA_CHANNEL_SMS = 1,

  /**
   * E-mail ("email")
   */
  TALER_MERCHANT_MFA_CHANNEL_EMAIL,

  /**
   * TOTP ("totp"). (Not yet implemented, #10327.)
   */
  TALER_MERCHANT_MFA_CHANNEL_TOTP
};


/**
 * Types of critical operations of a merchant backend that may require
 * multi-factor authorization.
 */
enum TALER_MERCHANT_MFA_CriticalOperation
{
  /**
   * Marker used to indicate that this is NOT a critical operation.
   */
  TALER_MERCHANT_MFA_CO_NONE = 0,

  /**
   * Instance provisioning ("instance_provision").
   */
  TALER_MERCHANT_MFA_CO_INSTANCE_PROVISION,

  /**
   * Bank account configuration or reconfiguration ("account_config").
   */
  TALER_MERCHANT_MFA_CO_ACCOUNT_CONFIGURATION,

  /**
   * Authentication configuration change ("auth_config").
   */
  TALER_MERCHANT_MFA_CO_AUTH_CONFIGURATION,

  /**
   * Instance deletion ("instance_deletion").
   */
  TALER_MERCHANT_MFA_CO_INSTANCE_DELETION,

  /**
   * Authentication token creation ("auth_token_creation").
   */
  TALER_MERCHANT_MFA_CO_AUTH_TOKEN_CREATION

};


/**
 * Possible versions of the contract terms.
 */
enum TALER_MERCHANT_ContractVersion
{

  /**
   * Version 0
   */
  TALER_MERCHANT_CONTRACT_VERSION_0 = 0,

  /**
   * Version 1
   */
  TALER_MERCHANT_CONTRACT_VERSION_1 = 1
};

/**
 * Possible token kinds.
 */
enum TALER_MERCHANT_ContractTokenKind
{
  /**
   * Token kind invalid
   */
  TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID = 0,

  /**
   * Subscription token kind
   */
  TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION = 1,

  /**
   * Discount token kind
   */
  TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT = 2,
};


/**
 * Get enum value from contract token type string.
 *
 * @param str contract token type string
 * @return enum value of token type
 */
enum TALER_MERCHANT_ContractTokenKind
TALER_MERCHANT_contract_token_kind_from_string (const char *str);


/**
 * Possible input types for the contract terms.
 */
enum TALER_MERCHANT_ContractInputType
{

  /**
   * Input type invalid
   */
  TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID = 0,

#if FUTURE
  /**
   * Input type coin
   */
  TALER_MERCHANT_CONTRACT_INPUT_TYPE_COIN = 1,
#endif
  /**
   * Input type token
   */
  TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN = 2
};

/**
 * Contract input (part of the v1 contract terms).
 */
struct TALER_MERCHANT_ContractInput
{
  /**
  * Type of the input.
  */
  enum TALER_MERCHANT_ContractInputType type;

  union
  {
#if FUTURE
    /**
     * Coin-based input (ration). (Future work, only here for reference)
     */
    struct
    {
      /**
      * Price to be paid.
      */
      struct TALER_Amount price;

      /**
      * Base URL of the ration authority.
      */
      const char *ration_authority_url;
    } coin;
#endif

    /**
     * Token-based input.
     */
    struct
    {
      /**
       * Slug of the token family to be used.
       */
      const char *token_family_slug;

      /**
       * Number of tokens of this type required. Defaults to one if the
       * field is not provided.
       */
      unsigned int count;
    } token;
  } details;
};


/**
 * Order input (part of the v1 orders).
 */
struct TALER_MERCHANT_OrderInput
{
  /**
  * Type of the input.
  */
  enum TALER_MERCHANT_ContractInputType type;

  union
  {
#if FUTURE
    /**
     * Coin-based input (ration). (Future work, only here for reference)
     */
    struct
    {
      /**
      * Price to be paid.
      */
      struct TALER_Amount price;

      /**
      * Base URL of the ration authority.
      */
      const char *ration_authority_url;
    } coin;
#endif

    /**
     * Token-based input.
     */
    struct
    {
      /**
       * Slug of the token family to be used.
       */
      const char *token_family_slug;

      /**
       * Number of tokens of this type required. Defaults to one if the
       * field is not provided.
       */
      unsigned int count;
    } token;
  } details;
};


/**
 * Possible output types for the contract terms.
 */
enum TALER_MERCHANT_ContractOutputType
{

  /**
   * Invalid output type
   */
  TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID = 0,

  /**
   * Output type token
   */
  TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN = 1,

  /**
   * Output type donation-receipt
   */
  TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT = 2,
#if FUTURE
  /**
   * Output type coin
   */
  TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_COIN = 3
#endif

};

/**
 * Contract output (part of the v1 contract terms).
 */
struct TALER_MERCHANT_ContractOutput
{
  /**
   * Type of the output.
   */
  enum TALER_MERCHANT_ContractOutputType type;

  union
  {
#if FUTURE
    /**
     * Coin-based output.
     */
    struct
    {
      /**
       * Coins that will be yielded. This excludes any applicable withdraw fees.
       */
      struct TALER_Amount brutto_yield;

      /**
       * Base URL of the exchange that will issue the coins.
       *
       * NOTE: Once implemented, check if we need to allocate this here or if
       * we again reference the JSON as we do in other places.
       */
      char *exchange_url;

    } coin;
#endif
    /**
     * DONAU-receipt output.
     */
    struct
    {
      /**
       * Amount of the donation.
       */
      struct TALER_Amount amount;

      /**
       * Base URLs of the donation authorities that will issue the tax receipt.
       */
      char **donau_urls;

      /**
       * Length of the @e donau_urls array.
       */
      unsigned int donau_urls_len;

    } donation_receipt;

    /**
     * Token-based output.
     */
    struct
    {
      /**
       * Slug of the token family to be issued.
       * Note: this is a pointer into the JSON of the
       * respective contract/request and not owned here.
       */
      const char *token_family_slug;

      /**
       * Index of the public key in the @a token_family_slug's token family
       * ``keys`` array that this output token will have.
       */
      unsigned int key_index;

      /**
       * Number of tokens of this type required. Defaults to one if the
       * field is not provided.
       */
      unsigned int count;

      /**
       * Determines when the output token should be valid.
       * Optional, set to zero for not specified (then we
       * use the current time).
       */
      struct GNUNET_TIME_Timestamp valid_at;

    } token;

  } details;

};


/**
 * Order output (part of the v1 orders).
 */
struct TALER_MERCHANT_OrderOutput
{
  /**
   * Type of the output.
   */
  enum TALER_MERCHANT_ContractOutputType type;

  union
  {
#if FUTURE
    /**
     * Coin-based output.
     */
    struct
    {
      /**
       * Coins that will be yielded. This excludes any applicable withdraw fees.
       */
      struct TALER_Amount brutto_yield;

      /**
       * Base URL of the exchange that will issue the coins.
       *
       * NOTE: Once implemented, check if we need to allocate this here or if
       * we again reference the JSON as we do in other places.
       */
      char *exchange_url;

    } coin;
#endif
    /**
     * DONAU-receipt output.
     */
    struct
    {
      /**
       * Amount of the donation. (optional)
       */
      struct TALER_Amount amount;

      /**
       * True if @e amount is NOT set.
       */
      bool no_amount;

    } donation_receipt;

    /**
     * Token-based output.
     */
    struct
    {
      /**
       * Slug of the token family to be issued.
       * Note: this is a pointer into the JSON of the
       * respective contract/request and not owned here.
       */
      const char *token_family_slug;

      /**
       * Number of tokens of this type required. Defaults to one if the
       * field is not provided.
       */
      unsigned int count;

      /**
       * Determines when the output token should be valid.
       * Optional, set to zero for not specified (then we
       * use the current time).
       */
      struct GNUNET_TIME_Timestamp valid_at;

    } token;

  } details;

};


/**
 * Contract choice (part of the v1 contract terms).
 */
struct TALER_MERCHANT_ContractChoice
{

  /**
   * Amount to be paid for this choice.
   */
  struct TALER_Amount amount;

  /**
   * Tip included by the customer (part of the total amount).
   */
  struct TALER_Amount tip;

  /**
   * True if @e tip was not provided.
   */
  bool no_tip;

  /**
   * Human readable description of the semantics of the choice within the
   * contract to be shown to the user at payment.
   */
  char *description;

  /**
   * Map from IETF BCP 47 language tags to localized description.
   * Optional.
   */
  json_t *description_i18n;

  /**
   * Maximum fee the merchant is willing to pay for this choice.
   * Set to an invalid amount to use instance defaults (zero or STEFAN).
   */
  struct TALER_Amount max_fee;

  /**
   * List of inputs the wallet must provision (all of them) to satisfy the
   * conditions for the contract.
   */
  struct TALER_MERCHANT_ContractInput *inputs;

  /**
   * Length of the @e inputs array.
   */
  unsigned int inputs_len;

  /**
   * List of outputs the merchant promises to yield (all of them) once
   * the contract is paid.
   */
  struct TALER_MERCHANT_ContractOutput *outputs;

  /**
   * Length of the @e outputs array.
   */
  unsigned int outputs_len;
};


/**
 * Order choice (part of the v1 order).
 */
struct TALER_MERCHANT_OrderChoice
{

  /**
   * Amount to be paid for this choice.
   */
  struct TALER_Amount amount;

  /**
   * Tip included by the customer (part of the total amount).
   */
  struct TALER_Amount tip;

  /**
   * True if @e tip was not provided.
   */
  bool no_tip;

  /**
   * Human readable description of the semantics of the choice within the
   * contract to be shown to the user at payment.
   */
  char *description;

  /**
   * Map from IETF BCP 47 language tags to localized description.
   * Optional.
   */
  json_t *description_i18n;

  /**
   * Maximum fee the merchant is willing to pay for this choice.
   * Set to an invalid amount to use instance defaults (zero or STEFAN).
   */
  struct TALER_Amount max_fee;

  /**
   * True if @e max_fee was not provided.
   */
  bool no_max_fee;

  /**
   * True if the client may replace @e amount when instantiating the
   * template this choice belongs to; @e amount then merely provides the
   * default.  Only meaningful for choices from a template contract,
   * never serialized into an order.
   */
  bool editable_amount;

  /**
   * List of inputs the wallet must provision (all of them) to satisfy the
   * conditions for the order.
   */
  struct TALER_MERCHANT_OrderInput *inputs;

  /**
   * Length of the @e inputs array.
   */
  unsigned int inputs_len;

  /**
   * List of outputs the merchant promises to yield (all of them) once
   * the order is paid.
   */
  struct TALER_MERCHANT_OrderOutput *outputs;

  /**
   * Length of the @e outputs array.
   */
  unsigned int outputs_len;
};


/**
 * Public key and corresponding metadata for a token family.
 */
struct TALER_MERCHANT_ContractTokenFamilyKey
{
  /**
   * Public key.
   */
  struct TALER_TokenIssuePublicKey pub;

  /**
   * Start time of the token family duration.
   */
  struct GNUNET_TIME_Timestamp valid_after;

  /**
   * Tokens signed by this key will be valid until this time.
   */
  struct GNUNET_TIME_Timestamp valid_before;
};


/**
 * Represents a family of tokens issued by merchants that can be used in contracts.
 */
struct TALER_MERCHANT_ContractTokenFamily
{
  /**
   * Slug of the token family.
   */
  char *slug;

  /**
   * Human-readable name of the token family.
   */
  char *name;

  /**
   * Human-readable description of the semantics of the tokens issued by
   * this token family.
   */
  char *description;

  /**
   * Map from IETF BCP 47 language tags to localized description.
   * Optional.
   */
  json_t *description_i18n;

  /**
   * Relevant public keys of this token family for the given contract.
   */
  struct TALER_MERCHANT_ContractTokenFamilyKey *keys;

  /**
   * Length of the @e keys array.
   */
  unsigned int keys_len;

  /**
   * Must a wallet understand this token type to process contracts that
   * consume or yield it?
   */
  bool critical;

  /**
   * Kind of the token family.
   */
  enum TALER_MERCHANT_ContractTokenKind kind;

  /**
   * Kind-specific information about the token.
   */
  union
  {
    /**
     * Subscription token.
     */
    struct
    {
      /**
       * Array of domain names where this subscription can be safely used
       * (e.g. the issuer warrants that these sites will re-issue tokens of
       * this type if the respective contract says so). May contain "*" for
       * any domain or subdomain.
       */
      char **trusted_domains;

      /**
       * Length of the @e trusted_domains array.
       */
      unsigned int trusted_domains_len;
    } subscription;

    /**
    * Discount token.
    */
    struct
    {
      /**
       * Array of domain names where this discount token is intended to be
       * used. May contain "*" for any domain or subdomain. Users should be
       * warned about sites proposing to consume discount tokens of this
       * type that are not in this list that the merchant is accepting a
       * coupon from a competitor and thus may be attaching different
       * semantics (like get 20% discount for my competitors 30% discount
       * token).
       */
      char **expected_domains;

      /**
       * Length of the @e expected_domains array.
       */
      unsigned int expected_domains_len;

    } discount;
  } details;
};

/**
 * Specifies the quantity of a product (to be) sold.
 */
struct TALER_MERCHANT_ProductQuantity
{
  /**
   * Integer component of the quantity.
   */
  uint64_t integer;

  /**
   * Fractional component of the quantity, in the
   * range of 0..TALER_MERCHANT_UNIT_FRAC_BASE-1.
   */
  uint32_t fractional;

};


/**
 * How to round when computing with amounts?
 */
enum TALER_MERCHANT_RoundMode
{
  TALER_MERCHANT_ROUND_NEAREST,
  TALER_MERCHANT_ROUND_UP,
  TALER_MERCHANT_ROUND_DOWN
};


/**
 * Template type discriminator.
 */
enum TALER_MERCHANT_TemplateType
{
  TALER_MERCHANT_TEMPLATE_TYPE_INVALID = 0,
  TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER,
  TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART,
  TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA
};

/**
 * Determine template type from string.
 *
 * @param template_type string value (NULL means fixed-order)
 * @return template type (defaults to fixed order)
 */
enum TALER_MERCHANT_TemplateType
TALER_MERCHANT_template_type_from_string (const char *template_type);

/**
 * Convert template type to its string representation.
 *
 * @param template_type template type to convert
 * @return string name or NULL for invalid types
 */
const char *
TALER_MERCHANT_template_type_to_string (
  enum TALER_MERCHANT_TemplateType template_type);

/**
 * Determine template type from a template contract.
 *
 * @param template_contract contract JSON
 * @return template type (defaults to fixed order)
 */
enum TALER_MERCHANT_TemplateType
TALER_MERCHANT_template_type_from_contract (const json_t *template_contract);


/**
 * Template contract fields for inventory templates.
 */
struct TALER_MERCHANT_TemplateContractInventory
{
  /**
   * Selected categories from the template contract.
   */
  const json_t *selected_categories;

  /**
   * Selected products from the template contract.
   */
  const json_t *selected_products;

  /**
   * Whether all products are selectable.
   */
  bool selected_all;

  /**
   * Template requires exactly one selection.
   */
  bool choose_one;

};

/**
 * Template contract fields for paivana templates.
 */
struct TALER_MERCHANT_TemplateContractPaivana
{
  /**
   * Paivana website regular expression.
   * NULL to allow any site.
   */
  const char *website_regex;

  /**
   * Array of possible specific contracts the wallet/customer may choose
   * from by selecting the respective index when signing the deposit
   * confirmation.
   */
  struct TALER_MERCHANT_OrderChoice *choices;

  /**
   * Length of the @e choices array.
   */
  unsigned int choices_len;

};

/**
 * Parsed template contract.
 */
struct TALER_MERCHANT_TemplateContract
{
  /**
   * Template type.
   */
  enum TALER_MERCHANT_TemplateType type;

  /**
   * Summary from the template contract.
   */
  const char *summary;

  /**
   * Currency from the template contract.
   */
  const char *currency;

  /**
   * Amount from the template contract.
   */
  struct TALER_Amount amount;

  /**
   * True if @e amount was not provided.
   */
  bool no_amount;

  /**
   * Smallest amount the client may end up paying (excluding tips)
   * when instantiating this template.  Only checked against amounts
   * the client had an influence on.
   */
  struct TALER_Amount min_amount;

  /**
   * True if @e min_amount was not provided.
   */
  bool no_min_amount;

  /**
   * Largest amount the client may end up paying (excluding tips)
   * when instantiating this template.  Only checked against amounts
   * the client had an influence on.
   */
  struct TALER_Amount max_amount;

  /**
   * True if @e max_amount was not provided.
   */
  bool no_max_amount;

  /**
   * Template allows tips.
   */
  bool request_tip;

  /**
   * Minimum age required by the template.
   */
  uint32_t minimum_age;

  /**
   * How long does the customer have to pay for the order.
   * 0 if not specified (use instance default).
   */
  struct GNUNET_TIME_Relative pay_duration;

  /**
   * How long does the user have at most to access/pickup the (digital)
   * goods or service they bought. Optional, defaults to FOREVER.
   */
  struct GNUNET_TIME_Relative max_pickup_duration;

  union
  {

    /**
     * Parsed fields for inventory templates.
     */
    struct TALER_MERCHANT_TemplateContractInventory inventory;

    /**
     * Parsed fields for paivana templates.
     */
    struct TALER_MERCHANT_TemplateContractPaivana paivana;

  } details;

};

/**
 * Parse template contract JSON into @a out.
 *
 * @param template_contract JSON object containing the template contract
 * @param[out] out parsed template contract
 * @param[out] error_name pointer to the name of the failed field, or NULL
 * @return #GNUNET_SYSERR if @a template_contract is malformed; #GNUNET_OK otherwise
 */
enum GNUNET_GenericReturnValue
TALER_MERCHANT_template_contract_parse (
  const json_t *template_contract,
  struct TALER_MERCHANT_TemplateContract *out,
  const char **error_name);


/**
 * Release memory from template contract @a tc.
 * Does not free @a tc itself.
 *
 * @param[in] tc contract to free
 */
void
TALER_MERCHANT_template_contract_free (
  struct TALER_MERCHANT_TemplateContract *tc);


/**
 * Check if @a template_contract is valid.
 *
 * @param template_contract template contract to validate
 * @return true if @a template_contract is valid
 */
bool
TALER_MERCHANT_template_contract_valid (const json_t *template_contract);


/**
 * Convert critical operation enumeration value to string
 * suitable for human readers.
 *
 * @param co input to convert
 * @return operation value as string
 */
const char *
TALER_MERCHANT_MFA_co2s (
  enum TALER_MERCHANT_MFA_CriticalOperation co);


/**
 * Convert critical operation enumeration value to string.
 *
 * @param co input to convert
 * @return operation value as string
 */
const char *
TALER_MERCHANT_MFA_co_to_string (
  enum TALER_MERCHANT_MFA_CriticalOperation co);


/**
 * Convert string to critical operation enumeration value.
 *
 * @param str input to convert
 * @return #TALER_MERCHANT_MFA_CO_NONE on failure
 */
enum TALER_MERCHANT_MFA_CriticalOperation
TALER_MERCHANT_MFA_co_from_string (const char *str);


/**
 * Convert MFA channel enumeration value to string.
 *
 * @param ch input to convert
 * @return operation value as string
 */
const char *
TALER_MERCHANT_MFA_channel_to_string (
  enum TALER_MERCHANT_MFA_Channel ch);


/**
 * Convert string to MFA channel enumeration value.
 *
 * @param str input to convert
 * @return #TALER_MERCHANT_MFA_CHANNEL_NONE on failure
 */
enum TALER_MERCHANT_MFA_Channel
TALER_MERCHANT_MFA_channel_from_string (const char *str);


/**
 * @brief Salted hash of a body for a request that required MFA.
 */
struct TALER_MERCHANT_MFA_BodyHash
{
  /**
   * Hash of the body and salt.
   */
  struct GNUNET_ShortHashCode hash;
};


/**
 * @brief Salt used when computing a `struct TALER_MERCHANT_MFA_BodyHash`
 */
struct TALER_MERCHANT_MFA_BodySalt
{
  /**
   * Salt.
   */
  uint64_t salt[128 / 64];
};


/**
 * @brief Token used to authorize report generation.
 */
struct TALER_MERCHANT_ReportToken
{
  /**
   * Salt.
   */
  uint64_t salt[256 / 64];
};


/**
 * Hash the given request @a body with the given @a salt to
 * produce @a h_body for MFA checks.
 *
 * @param body HTTP request body, NULL if body was empty
 * @param salt salt to use
 * @param h_body resulting hash
 */
void
TALER_MERCHANT_mfa_body_hash (
  const json_t *body,
  const struct TALER_MERCHANT_MFA_BodySalt *salt,
  struct TALER_MERCHANT_MFA_BodyHash *h_body);


/**
 * Multiply the @a unit_price by the quantity given in @a factor.
 * Round the result using the given rounding mode @a rm to a
 * multiple of the @a atomic_amount.
 *
 * @param[out] result where to store the result
 * @param unit_price price for one item
 * @param factor quantity to purchase, can be factional
 * @param rm rounding mode to apply
 * @param atomic_amount granularity to round to
 * @return #GNUNET_OK on success
 *   #GNUNET_NO on integer overflow (resulting amount cannot be represented)
 *   #GNUNET_SYSERR on internal failure (e.g. currency
 *     @a unit_price and @a atomic_amount do not match)
 */
enum GNUNET_GenericReturnValue
TALER_MERCHANT_amount_multiply_by_quantity (
  struct TALER_Amount *result,
  const struct TALER_Amount *unit_price,
  const struct TALER_MERCHANT_ProductQuantity *factor,
  enum TALER_MERCHANT_RoundMode rm,
  const struct TALER_Amount *atomic_amount);


/**
 * Details about a product (to be) sold.  This structure represents
 * both the MinimalInventoryProduct and the ProductSold. Note that
 * the two have different mandatory and/or optional fields but are
 * both possible in `struct TALER_MERCHANT_Order`. However, only
 * ProductSold is allowed in the contracts.
 */
struct TALER_MERCHANT_ProductSold
{

  /**
   * Merchant-internal identifier for the product. NULL for none.
   */
  char *product_id;

  /**
   * Name of the product. NULL for pre **v20** contract terms.
   */
  char *product_name;

  /**
   * Human-readable product description.
   */
  char *description;

  /**
   * Map from IETF BCP 47 language tags to localized descriptions.
   * NULL if no translations are available.
   */
  json_t *description_i18n;

  /**
   * Quantity (in multiples of @e unit) to be sold.
   */
  struct TALER_MERCHANT_ProductQuantity unit_quantity;

  /**
   * Unit in which the product is measured (liters, kilograms, packages,
   * etc.). Can be NULL if not specified.
   */
  char *unit;

  /**
   * Length of the @e prices array.
   */
  unsigned int prices_length;

  /**
   * Array of prices (in different currencies) for @e unit_quantity
   * units of this product (these are longer the per-unit prices!).
   */
  struct TALER_Amount *prices;

  /**
   * True if the @e prices given are the net price,
   * false if they are the gross price.  Note that even @e prices are the
   * gross price, @e taxes may be missing if the merchant configured
   * gross @e prices but did not configure any @e taxes.
   * Similarly, the merchant may have configured net @e prices
   * for products but deals with taxes on a per-order basis. Thus, it
   * may not always be possible to compute the gross price from the net
   * price for an individual product, necessitating this flag.
   */
  bool prices_are_net;

  /**
   * An optional base64-encoded image of the product.
   */
  char *image;

  /**
   * A list of taxes paid by the merchant for this product. Can be NULL.
   * Will likely change soon!
   */
  json_t *taxes;

  /**
   * Time indicating when this product should be delivered.
   * #GNUNET_TIME_UNIT_FOREVER_TS for unknown / not specified.
   */
  struct GNUNET_TIME_Timestamp delivery_date;

  /**
   * Money pot to use for this product, overrides value from
   * the inventory if given.  Not useful to wallets, only for
   * merchant-internal accounting.
   */
  uint64_t product_money_pot;

};


/**
 * Merchant information.
 */
struct TALER_MERCHANT_MetaData
{
  /**
   * Legal name of the instance
   */
  char *name;

  /**
   * Merchant's site url
   */
  char *website;

  /**
   * Email contact for customers
   */
  char *email;

  /**
   * merchant's logo data uri
   */
  char *logo;

  /**
   * Merchant address
   */
  json_t *address;

  /**
   * Jurisdiction of the business
   */
  json_t *jurisdiction;

};


/**
 * Struct to hold terms common to both orders and contracts and
 * are basically present (or optional) all the time.
 */
struct TALER_MERCHANT_ContractBaseTerms
{

  /**
   * Version of the contract terms.
   */
  enum TALER_MERCHANT_ContractVersion version;

  /**
   * Summary of the contract.
   */
  char *summary;

  /**
   * Internationalized summary. Optional.
   */
  json_t *summary_i18n;

  /**
   * URL where the same contract could be ordered again (if available).
   * Optional.
   */
  char *public_reorder_url;

  /**
   * URL that will show that the contract was successful
   * after it has been paid for.
   * Optional.
   */
  char *fulfillment_url;

  /**
   * Message shown to the customer after paying for the contract.
   * Either fulfillment_url or fulfillment_message must be specified.
   * Optional.
   */
  char *fulfillment_message;

  /**
   * Map from IETF BCP 47 language tags to localized fulfillment messages.
   * Optional.
   */
  json_t *fulfillment_message_i18n;

  /**
   * Delivery location.
   * Optional.
   */
  json_t *delivery_location;

  /**
   * Delivery date.
   * Optional.
   */
  struct GNUNET_TIME_Timestamp delivery_date;

  /**
   * Specifies for how long the wallet should try to get an
   * automatic refund for the purchase.
   * Optional, zero if not applicable.
   */
  struct GNUNET_TIME_Relative auto_refund;

  /**
   * Extra data that is only interpreted by the merchant frontend.
   */
  json_t *extra;

  /**
   * Minimum age the buyer must have (in years).
   */
  uint8_t minimum_age;

  /**
   * Default money pot to use for this order, applies to the
   * amount remaining that was not claimed by money pots of
   * products or taxes.  Not useful to wallets, only for
   * merchant-internal accounting.  If zero, the remaining
   * account is simply not accounted for in any money pot.
   */
  uint64_t default_money_pot;

  /**
   * Latest time until which the good or service may be
   * picked up by the customer. This is usually for digital
   * goods where the customer has a finite window for downloading.
   * Optional. FOREVER if not set.
   */
  struct GNUNET_TIME_Timestamp max_pickup_time;

};


/**
 * Struct to hold an order.
 */
struct TALER_MERCHANT_Order
{

  /**
   * Shared base terms of contracts and orders.
   */
  struct TALER_MERCHANT_ContractBaseTerms *base;

  /**
   * Our order ID. Optional.
   */
  char *order_id;

  /**
   * Array of products that are part of the purchase.
   */
  struct TALER_MERCHANT_ProductSold *products;

  /**
   * Length of the @e products array.
   */
  size_t products_len;

  /**
   * Timestamp of the contract.
   * Optional. Set to "now" on parsing if not given.
   */
  struct GNUNET_TIME_Timestamp timestamp;

  /**
   * Deadline for refunds.
   * Optional. Set to FOREVER if not given.
   */
  struct GNUNET_TIME_Timestamp refund_deadline;

  /**
   * Payment deadline.
   * Optional. Set to zero if not given.
   */
  struct GNUNET_TIME_Timestamp pay_deadline;

  /**
   * Wire transfer deadline.
   * Optional. Set to FOREVER if not given.
   */
  struct GNUNET_TIME_Timestamp wire_transfer_deadline;

  /**
   * Details depending on the @e base.version.
   */
  union
  {

    /**
     * Details for v0 orders.
     */
    struct
    {

      /**
       * Price to be paid for the transaction. Could be 0. The price is in addition
       * to other instruments, such as rations and tokens.
       * The exchange will subtract deposit fees from that amount
       * before transferring it to the merchant.
       */
      struct TALER_Amount brutto;

      /**
       * Tip included by the customer (part of the total amount).
       */
      struct TALER_Amount tip;

      /**
       * True if @e tip was not provided.
       */
      bool no_tip;

      /**
       * Maximum fee as given by the client request.
       */
      struct TALER_Amount max_fee;

      /**
       * True if @e max_fee was not provided.
       */
      bool no_max_fee;

    } v0;

    /**
     * Details for v1 contracts.
     */
    struct
    {

      /**
       * Array of possible specific payment choices the wallet/customer may choose
       * from by selecting the respective index when signing the deposit
2       * confirmation.
       */
      struct TALER_MERCHANT_OrderChoice *choices;

      /**
       * Length of the @e choices array.
       */
      unsigned int choices_len;

    } v1;

  } details;

};


/**
 * Struct to hold proto-contracts.
 */
struct TALER_MERCHANT_ProtoContract
{

  /**
   * Shared base terms of contracts and orders.
   */
  struct TALER_MERCHANT_ContractBaseTerms *base;

  /**
   * Our order ID.
   */
  char *order_id;

  /**
   * Timestamp of the contract.
   */
  struct GNUNET_TIME_Timestamp timestamp;

  /**
   * Deadline for refunds.
   */
  struct GNUNET_TIME_Timestamp refund_deadline;

  /**
   * Payment deadline.
   */
  struct GNUNET_TIME_Timestamp pay_deadline;

  /**
   * Wire transfer deadline.
   */
  struct GNUNET_TIME_Timestamp wire_deadline;

  /**
   * Merchant public key.
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Merchant base URL.
   */
  char *merchant_base_url;

  /**
   * Metadata about the merchant.
   */
  struct TALER_MERCHANT_MetaData merchant;

  /**
   * Array of products that are part of the purchase.
   */
  struct TALER_MERCHANT_ProductSold *products;

  /**
   * Length of the @e products array.
   */
  size_t products_len;

  /**
   * The hash of the merchant instance's wire details.
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * Wire transfer method identifier for the wire method associated with
   * @e h_wire.
   */
  char *wire_method;

  /**
   * Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
   * TODO: appropriate type
   */
  json_t *exchanges;

  /**
   * Details depending on the @e version.
   */
  union
  {

    /**
     * Details for v0 contracts.
     */
    struct
    {

      /**
       * Price to be paid for the transaction. Could be 0. The price is in addition
       * to other instruments, such as rations and tokens.
       * The exchange will subtract deposit fees from that amount
       * before transferring it to the merchant.
       */
      struct TALER_Amount brutto;

      /**
       * Tip included by the customer (part of the total amount).
       */
      struct TALER_Amount tip;

      /**
       * True if @e tip was not provided.
       */
      bool no_tip;

      /**
       * Maximum fee as given by the client request.
       */
      struct TALER_Amount max_fee;

    } v0;

    /**
     * Details for v1 contracts.
     */
    struct
    {

      /**
       * Array of possible specific contracts the wallet/customer may choose
       * from by selecting the respective index when signing the deposit
       * confirmation.
       */
      struct TALER_MERCHANT_ContractChoice *choices;

      /**
       * Length of the @e choices array.
       */
      unsigned int choices_len;

      /**
       * Array of token authorities.
       */
      struct TALER_MERCHANT_ContractTokenFamily *token_authorities;

      /**
       * Length of the @e token_authorities array.
       */
      unsigned int token_authorities_len;

    } v1;

  } details;

};


/**
 * Struct to hold contract terms.
 */
struct TALER_MERCHANT_Contract
{

  /**
   * The proto-contract.
   */
  struct TALER_MERCHANT_ProtoContract *pc;

  /**
   * Nonce generated by the wallet and echoed by the merchant
   * in this field when the proposal is generated.
   */
  char *nonce;

};


/**
 * Provide specification to parse an JSON contract input type.
 * The value is provided as a descriptive string.
 *
 * @param name name of the JSON member with the contract type
 * @param[out] cit where to store the contract input type
 * @return spec for parsing a contract input type
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_json_spec_cit (
  const char *name,
  enum TALER_MERCHANT_ContractInputType *cit);


/**
 * Create JSON specification to parse a merchant contract
 * version.
 *
 * @param name name of the field
 * @param[out] version where to write the contract version
 * @return JSON specification object
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_spec_contract_version (
  const char *name,
  enum TALER_MERCHANT_ContractVersion *version);


/**
 * Provide specification to parse given JSON object to merchant details in the
 * order terms. All fields from @a order are copied.
 *
 * @param name name of the merchant details field in the JSON
 * @param[out] order where the merchant details have to be written
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_spec_merchant_details (
  const char *name,
  struct TALER_MERCHANT_MetaData *merchant);


/**
 * Get JSON representation of merchant details.
 *
 * @param[in] merchant metadata to serialize
 * @return JSON object with merchant details; NULL on error
 */
json_t *
TALER_MERCHANT_metadata_to_json (
  const struct TALER_MERCHANT_MetaData *merchant);


/**
 * Free representation of merchant details.
 *
 * @param[in,out] merchant metadata to release, excluding the pointer itself
 */
void
TALER_MERCHANT_metadata_free (
  struct TALER_MERCHANT_MetaData *merchant);


/**
 * Provide specification to parse given JSON array to order
 * choices. All fields from @a choices elements are copied.
 *
 * @param name name of the choices field in the JSON
 * @param[out] choices where the order choices array has to be written
 * @param[out] choices_len length of the @a choices array
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_spec_order_choices (
  const char *name,
  struct TALER_MERCHANT_OrderChoice **choices,
  unsigned int *choices_len);


/**
 * Provide specification to parse given JSON array to contract terms
 * choices. All fields from @a choices elements are copied.
 *
 * @param name name of the choices field in the JSON
 * @param[out] choices where the contract choices array has to be written
 * @param[out] choices_len length of the @a choices array
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_spec_contract_choices (
  const char *name,
  struct TALER_MERCHANT_ContractChoice **choices,
  unsigned int *choices_len);


/**
 * Provide specification to parse given JSON array to token families in the
 * contract terms. All fields from @a families items are copied.
 *
 * @param name name of the token families field in the JSON
 * @param[out] families where the token families array has to be written
 * @param[out] families_len length of the @a families array
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_spec_token_families (
  const char *name,
  struct TALER_MERCHANT_ContractTokenFamily **families,
  unsigned int *families_len);


/**
 * Check if @a taxes is an array of valid Taxes in the sense of
 * Taler's API definition.
 *
 * @param taxes array to check
 * @return true if @a taxes is an array and all
 *         entries are valid Taxes.
 */
bool
TALER_MERCHANT_taxes_array_valid (
  const json_t *taxes);


/**
 * Provide specification to parse an JSON contract output type.
 * The value is provided as a descriptive string.
 *
 * @param name name of the JSON member with the contract type
 * @param[out] cot where to store the contract output type
 * @return spec for parsing a contract output type
 */
struct GNUNET_JSON_Specification
TALER_MERCHANT_json_spec_cot (
  const char *name,
  enum TALER_MERCHANT_ContractOutputType *cot);


/**
 * Get JSON representation of contract choice.
 *
 * @param[in] choice contract choice to serialize
 * @param order whether @a choice is contained in order or contract terms
 * @return JSON representation of @a choice; NULL on error
 */
json_t *
TALER_MERCHANT_json_from_contract_choice (
  const struct TALER_MERCHANT_ContractChoice *choice);


/**
 * Free all the fields in the given @a choice, but not @a choice itself, since
 * it is normally part of an array.
 *
 * @param[in] choice contract terms choice to free
 */
void
TALER_MERCHANT_contract_choice_free (
  struct TALER_MERCHANT_ContractChoice *choice);


/**
 * Get JSON representation of an order choice.
 *
 * @param[in] choice contract choice to serialize
 * @return JSON representation of @a choice; NULL on error
 */
json_t *
TALER_MERCHANT_json_from_order_choice (
  const struct TALER_MERCHANT_OrderChoice *choice);


/**
 * Free all the fields in the given @a choice, but not @a choice itself, since
 * it is normally part of an array.
 *
 * @param[in] choice contract terms choice to free
 */
void
TALER_MERCHANT_order_choice_free (
  struct TALER_MERCHANT_OrderChoice *choice);


/**
 * Get JSON representation of contract token family.
 *
 * @param[in] family contract token family to serialize
 * @return JSON representation of @a family; NULL on error
 */
json_t *
TALER_MERCHANT_json_from_token_family (
  const struct TALER_MERCHANT_ContractTokenFamily *family);


/**
 * Find token family in contract terms from slug and validity date.
 *
 * @param slug slug of the token family
 * @param valid_after validity start of the token family
 * @param[in] families array of token families in the contract terms
 * @param families_len length of @a families array
 * @param[out] family matching token family; NULL if no result;
 *   the pointer returned will be an alias into @e families
 * @param[out] key key of matching token family; NULL if no result
 * @return #GNUNET_SYSERR if no matching family found; #GNUNET_OK otherwise
 */
enum GNUNET_GenericReturnValue
TALER_MERCHANT_find_token_family_key (
  const char *slug,
  struct GNUNET_TIME_Timestamp valid_after,
  const struct TALER_MERCHANT_ContractTokenFamily *families,
  unsigned int families_len,
  struct TALER_MERCHANT_ContractTokenFamily *family,
  struct TALER_MERCHANT_ContractTokenFamilyKey *key);


/**
 * Free all the fields in the given @a family, but not @a family itself, since
 * it is normally part of an array.
 *
 * @param[in] family contract token family to free
 */
void
TALER_MERCHANT_contract_token_family_free (
  struct TALER_MERCHANT_ContractTokenFamily *family);


/**
 * Parse JSON product given in @a p, returning the result in
 * @a r.
 *
 * @param p JSON specifying a ``ProductSold`` to parse
 * @param[out] r where to write the result
 * @param allow_mip true to allow for MinimalInventoryProduct
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TALER_MERCHANT_parse_product_sold (
  const json_t *p,
  struct TALER_MERCHANT_ProductSold *r,
  bool allow_mip);


/**
 * Serialize @a p to JSON.
 *
 * @param p product to serialize
 * @return JSON object representing the product @a p
 */
json_t *
TALER_MERCHANT_product_sold_serialize (
  const struct TALER_MERCHANT_ProductSold *p);


/**
 * Release memory inside of @a product, but not @a product itself.
 *
 * @param[in] product data structure to clean up
 */
void
TALER_MERCHANT_product_sold_free (
  struct TALER_MERCHANT_ProductSold *product);


/**
 * Parse base terms (of orders and contracts) in @a input.
 *
 * @param[in] input JSON object containing contract terms
 * @return NULL if @a input is malformed
 */
struct TALER_MERCHANT_ContractBaseTerms *
TALER_MERCHANT_base_terms_parse (
  json_t *input);


/**
 * Serialize contract base terms into JSON object.
 *
 * @param[in] ct base contract terms to serialize
 * @return JSON representation of @a ct; NULL on error
 */
json_t *
TALER_MERCHANT_base_terms_serialize (
  const struct TALER_MERCHANT_ContractBaseTerms *ct);


/**
 * Release memory in @a ct
 *
 * @param[in] ct common terms to clean up
 */
void
TALER_MERCHANT_base_terms_free (
  struct TALER_MERCHANT_ContractBaseTerms *ct);


/**
 * Parse JSON order in @a input.
 *
 * @param[in] input JSON object containing an order
 * @return parsed contract terms; NULL if @a input is malformed
 */
struct TALER_MERCHANT_Order *
TALER_MERCHANT_order_parse (
  json_t *input);


#if NOT_NEEDED_YET
/**
 * Serialize order into JSON object.
 *
 * @param[in] input contract terms to serialize
 * @param nonce_optional whether `nonce' field is optional
 * @return JSON representation of @a input; NULL on error
 */
json_t *
TALER_MERCHANT_order_serialize (
  const struct TALER_MERCHANT_Order *input);

#endif


/**
 * Free the @a order and all fields in it.
 *
 * @param[in] order order to free
 */
void
TALER_MERCHANT_order_free (
  struct TALER_MERCHANT_Order *order);


/**
 * Parse JSON proto contract terms in @a input.
 *
 * @param[in] input JSON object containing contract terms
 * @return NULL on failure
 */
struct TALER_MERCHANT_ProtoContract *
TALER_MERCHANT_proto_contract_parse (
  json_t *input);


/**
 * Serialize proto contract into JSON object.
 *
 * @param[in] pc proto contract to serialize
 * @return JSON representation of @a pc; NULL on error
 */
json_t *
TALER_MERCHANT_proto_contract_serialize (
  const struct TALER_MERCHANT_ProtoContract *pc);


/**
 * Free the proto-contract at @a pc
 *
 * @param[in] pc proto-contract to free
 */
void
TALER_MERCHANT_proto_contract_free (
  struct TALER_MERCHANT_ProtoContract *pc);


/**
 * Parse JSON contract terms in @a input.
 *
 * @param[in] input JSON object containing contract terms
 * @return parsed contract terms; NULL if @a input is malformed
 */
struct TALER_MERCHANT_Contract *
TALER_MERCHANT_contract_parse (
  json_t *input);


/**
 * Serialize contract terms into JSON object.
 *
 * @param[in] input contract terms to serialize
 * @return JSON representation of @a input; NULL on error
 */
json_t *
TALER_MERCHANT_contract_serialize (
  const struct TALER_MERCHANT_Contract *input);


/**
 * Free the @a contract and all fields in it.
 *
 * @param[in] contract contract to free
 */
void
TALER_MERCHANT_contract_free (
  struct TALER_MERCHANT_Contract *contract);


#endif
