/*
  This file is part of TALER
  Copyright (C) 2014, 2015, 2016, 2020 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 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.GPL.  If not, see <http://www.gnu.org/licenses/>
*/

/**
 * @file src/include/merchantdb_lib.h
 * @brief database helper functions used by the merchant backend
 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
 */
#ifndef TALER_MERCHANTDB_LIB_H
#define TALER_MERCHANTDB_LIB_H

#include <gnunet/gnunet_pq_lib.h>
#include <taler/taler_util.h>

/**
 * Handle to interact with the database.
 */
struct TALER_MERCHANTDB_PostgresContext;

GNUNET_NETWORK_STRUCT_BEGIN

/**
 * Format of the data hashed to generate the notification
 * string whenever the KYC status for an account has
 * changed.
 */
struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP
{
  /**
   * Type is TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Salted hash of the affected account.
   */
  struct TALER_MerchantWireHashP h_wire;
};

/**
 * 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;
};


GNUNET_NETWORK_STRUCT_END


/**
 * Connect to postgresql database
 *
 * @param cfg the configuration handle
 * @return connection to the database; NULL upon error
 */
struct TALER_MERCHANTDB_PostgresContext *
TALER_MERCHANTDB_connect (
  const struct GNUNET_CONFIGURATION_Handle *cfg);

/**
 * Connect to postgresql database for administration.
 * Disables the check that the database schema is current.
 *
 * @param cfg the configuration handle
 * @return connection to the database; NULL upon error
 */
struct TALER_MERCHANTDB_PostgresContext *
TALER_MERCHANTDB_connect_admin (
  const struct GNUNET_CONFIGURATION_Handle *cfg);


/**
 * Disconnect from the database
 *
 * @param pg database handle to close
 */
void
TALER_MERCHANTDB_disconnect (struct TALER_MERCHANTDB_PostgresContext *pg);


void
check_connection (struct TALER_MERCHANTDB_PostgresContext *pg);


/**
 * Possible token family kinds.
 */
enum TALER_MERCHANTDB_TokenFamilyKind
{

  /**
   * Token family representing a discount token
   */
  TALER_MERCHANTDB_TFK_Discount = 0,

  /**
   * Token family representing a subscription token
   */
  TALER_MERCHANTDB_TFK_Subscription = 1,

};

/**
 * Results from trying to increase a refund.
 */
enum TALER_MERCHANTDB_RefundStatus
{

  /**
   * Refund amount exceeds legal exchange limits.
   */
  TALER_MERCHANTDB_RS_LEGAL_FAILURE = -5,

  /**
   * Refund amount currency does not match original payment.
   */
  TALER_MERCHANTDB_RS_BAD_CURRENCY = -4,

  /**
   * Refund amount exceeds original payment.
   */
  TALER_MERCHANTDB_RS_TOO_HIGH = -3,

  /**
   * Hard database failure.
   */
  TALER_MERCHANTDB_RS_HARD_ERROR = -2,

  /**
   * Soft database failure.
   */
  TALER_MERCHANTDB_RS_SOFT_ERROR = -1,

  /**
   * Order not found.
   */
  TALER_MERCHANTDB_RS_NO_SUCH_ORDER = 0,

  /**
   * Refund is now at or above the requested amount.
   */
  TALER_MERCHANTDB_RS_SUCCESS = 1

};

/**
 * Results from trying to store a deposit confirmation.
 * Values that also exist in `enum GNUNET_DB_QueryStatus`
 * intentionally use the same numeric value.
 */
enum TALER_MERCHANTDB_DepositConfirmationStatus
{

  /**
   * A deposit confirmation for this order and exchange
   * exists, but with conflicting details (timestamp, wire
   * deadline, wire fee or target account).
   */
  TALER_MERCHANTDB_DCS_CONFLICT = -6,

  /**
   * The exchange signing key that signed the deposit
   * confirmation is not known to us.
   */
  TALER_MERCHANTDB_DCS_NO_SIGNKEY = -5,

  /**
   * The merchant account the deposit was made to is
   * not known to us.
   */
  TALER_MERCHANTDB_DCS_NO_ACCOUNT = -4,

  /**
   * The order (contract) the deposit is for is not
   * known to us.
   */
  TALER_MERCHANTDB_DCS_NO_ORDER = -3,

  /**
   * Hard database failure.
   */
  TALER_MERCHANTDB_DCS_HARD_ERROR = -2,

  /**
   * Soft database failure, retry.
   */
  TALER_MERCHANTDB_DCS_SOFT_ERROR = -1,

  /**
   * The stored procedure did not return a row at all.
   * Should be impossible.
   */
  TALER_MERCHANTDB_DCS_NO_RESULTS = 0,

  /**
   * Deposit confirmation is now in the database.
   */
  TALER_MERCHANTDB_DCS_SUCCESS = 1

};

/**
 * Results from associating a deposit with a wire transfer.
 * Values that also exist in `enum GNUNET_DB_QueryStatus`
 * intentionally use the same numeric value.
 */
enum TALER_MERCHANTDB_DepositToTransferStatus
{

  /**
   * Hard database failure.
   */
  TALER_MERCHANTDB_DTTS_HARD_ERROR = -2,

  /**
   * Soft database failure, retry.
   */
  TALER_MERCHANTDB_DTTS_SOFT_ERROR = -1,

  /**
   * The stored procedure did not return a row at all.
   * Should be impossible.
   */
  TALER_MERCHANTDB_DTTS_NO_RESULTS = 0,

  /**
   * The deposit was associated with the wire transfer.
   */
  TALER_MERCHANTDB_DTTS_SETTLED = 1,

  /**
   * The exchange signing key is (still) unknown to us; the
   * deposit was scheduled for a retry.
   */
  TALER_MERCHANTDB_DTTS_SIGNKEY_UNKNOWN = 2,

  /**
   * The exchange wired the money to an account we do not know.
   * This is a permanent failure: the deposit will never settle
   * and the order must not be considered wired.
   */
  TALER_MERCHANTDB_DTTS_ACCOUNT_UNKNOWN = 3

};

/**
 * Details about an OTP device.
 */
struct TALER_MERCHANTDB_OtpDeviceDetails
{

  /**
   * Description of the device.
   */
  char *otp_description;

  /**
   * Current usage counter value.
   */
  uint64_t otp_ctr;

  /**
   * Base64-encoded key.
   */
  char *otp_key;

  /**
   * Algorithm used to compute purchase confirmations.
   */
  enum TALER_MerchantConfirmationAlgorithm otp_algorithm;
};


/**
 * Details about a template.
 */
struct TALER_MERCHANTDB_TemplateDetails
{
  /**
   * Description of the template.
   */
  char *template_description;

  /**
   * In this template contract, we can have additional information.
   */
  json_t *template_contract;

  /**
   * ID of the OTP device linked to the template, or NULL.
   */
  char *otp_id;

  /**
   * Editable default values for fields not specified
   * in the @e template_contract. NULL if the user
   * cannot edit anything.
   */
  json_t *editable_defaults;

};


/**
 * Structure to hold Donau instance details from the database.
 */
struct TALER_MERCHANTDB_DonauInstance
{
  /**
   * Donau instance serial
   */
  uint64_t donau_instance_serial;

  /**
   * The URL for the Donau instance.
   */
  char *donau_url;

  /**
   * The name of the charity associated with the Donau instance.
   */
  char *charity_name;

  /**
   * Pointer to the public key of the charity, used for cryptographic operations.
   * This is represented as an EDDSA public key structure.
   */
  struct DONAU_CharityPublicKeyP *charity_pub_key;

  /**
   * A unique identifier for the charity in the Donau instance.
   */
  uint64_t charity_id;

  /**
   * The maximum allowable amount for donations to this charity in the current year.
   * This is tracked for regulatory or internal business constraints.
   */
  struct TALER_Amount charity_max_per_year;

  /**
   * The total amount of donations received by the charity in the current year.
   * This field helps track progress toward the yearly donation limit.
   */
  struct TALER_Amount charity_receipts_to_date;

  /**
   * The current year being tracked for donations.
   * This is used to differentiate donation data between years.
   */
  int64_t current_year;

  /**
   * A JSON object containing key information specific to the Donau instance,
   * such as cryptographic keys or other relevant details.
   */
  json_t *donau_keys_json;
};


/**
 * Details about a product.
 *
 * FIXME: reuse TALER_MERCHANT_Product as a member in this structure!
 */
struct TALER_MERCHANTDB_ProductDetails
{
  /**
   * Name of the product.
   */
  char *product_name;

  /**
   * Description of the product.
   */
  char *description;

  /**
   * Internationalized description.
   */
  json_t *description_i18n;

  /**
   * Unit in which the product is sold.
   */
  char *unit;

  /**
   * Optional list of per-unit prices. When NULL or empty, @e price
   * must be used as the canonical single price.
   */
  struct TALER_Amount *price_array;

  /**
   * Number of entries in @e price_array.
   */
  size_t price_array_length;

  /**
   * Base64-encoded product image, or an empty string.
   */
  char *image;

  /**
   * Hash of the product image data, or NULL.
   */
  char *image_hash;

  /**
   * List of taxes the merchant pays for this product. Never NULL,
   * but can be an empty array.
   */
  json_t *taxes;

  /**
   * Number of units of the product in stock in sum in total, including all
   * existing sales and lost product, in product-specific units. UINT64_MAX
   * indicates "infinite".
   */
  uint64_t total_stock;

  /**
   * Fractional part of stock in units of 1/1000000 of the base value.
   */
  uint32_t total_stock_frac;

  /**
   * Honor fractional stock if TRUE, else only integer stock.
   */
  bool allow_fractional_quantity;

  /**
   * Precision level (number of decimal places) to apply when
   * fractional quantities are enabled.
   */
  uint32_t fractional_precision_level;

  /**
   * Number of units of the product in sold, in product-specific units.
   */
  uint64_t total_sold;

  /**
   * Fractional part of units sold in units of 1/1000000 of the base value.
   */
  uint32_t total_sold_frac;

  /**
   * Number of units of stock lost.
   */
  uint64_t total_lost;

  /**
   * Fractional part of lost units in units of 1/1000000 of the base value.
   */
  uint32_t total_lost_frac;

  /**
   * Number of units currently reserved by locks (shopping cart locks and
   * locks held by unpaid orders).  These units are unavailable for new
   * orders.  Maintained by the database, not set by the application.
   */
  uint64_t total_locked;

  /**
   * Fractional part of locked units in units of 1/1000000 of the base value.
   */
  uint32_t total_locked_frac;

  /**
   * Identifies where the product is in stock, possibly an empty map.
   */
  json_t *address;

  /**
   * Identifies when the product will be restocked. 0 for unknown,
   * #GNUNET_TIME_UNIT_FOREVER_ABS for never.
   */
  struct GNUNET_TIME_Timestamp next_restock;

  /**
   * Minimum required age for consumers buying this product.
   * Default is 0. Only enforced of an exchange supports age
   * restrictions.
   */
  uint32_t minimum_age;

  /**
   * Group in which the product is in. 0 for default group.
   */
  uint64_t product_group_id;

  /**
   * Money pot into which sales of this product should go into by default.
   */
  uint64_t money_pot_id;

  /**
   * True if the price for this product is given in net,
   * False if its the gross price.
   */
  bool price_is_net;

};


/**
 * Details about a webhook.
 */
struct TALER_MERCHANTDB_WebhookDetails
{

  /**
   * event of the webhook.
   */
  char *event_type;

  /**
   * URL of the webhook. The customer will be redirected on this url.
   */
  char *url;

  /**
   * Http method used by the webhook.
   */
  char *http_method;

  /**
   * Header template of the webhook.
   */
  char *header_template;

  /**
   * Body template of the webhook.
   */
  char *body_template;

};


/**
 * Details about a product category.
 */
struct TALER_MERCHANTDB_CategoryDetails
{

  /**
   * Name of the category.
   */
  char *category_name;

  /**
   * Translations of the name of the category.
   */
  json_t *category_name_i18n;

};


/**
 * Details about the pending webhook.
 */
struct TALER_MERCHANTDB_PendingWebhookDetails
{

  /**
   * Identifies when we should make the next request to the webhook. 0 for unknown,
   * #GNUNET_TIME_UNIT_FOREVER_ABS for never.
   */
  struct GNUNET_TIME_Absolute next_attempt;

  /**
   * How often have we tried this request so far.
   */
  uint32_t retries;

  /**
   * URL of the webhook. The customer will be redirected on this url.
   */
  char *url;

  /**
   * Http method used for the webhook.
   */
  char *http_method;

  /**
   * Header of the webhook.
   */
  char *header;

  /**
   * Body of the webhook.
   */
  char *body;

};


/**
 * Details about a token family.
 */
struct TALER_MERCHANTDB_TokenFamilyDetails
{
  /**
   * Token family slug used for identification.
   */
  char *slug;

  /**
   * User readable name of the token family.
   */
  char *name;

  /**
   * Description of the token family.
   */
  char *description;

  /**
   * Internationalized token family description.
   */
  json_t *description_i18n;

  /**
   * Meta-data associated with the token family.
   * Includes information like "trusted_domains" or
   * "expected_domains", if set.
   */
  json_t *extra_data;

  /**
   * Cipher that should be used for this token family.  Note: We do not expose
   * this over the API and do not let clients set it. NULL for default (when
   * calling database).
   */
  char *cipher_spec;

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

  /**
   * End time of the token family duration.
   */
  struct GNUNET_TIME_Timestamp valid_before;

  /**
   * Validity duration of the token family. Must be larger or
   * equal to @a rounding plus @a start_offset_s.
   */
  struct GNUNET_TIME_Relative duration;

  /**
   * Rounding duration of the token family.
   */
  struct GNUNET_TIME_Relative validity_granularity;

  /**
   * Offset (in seconds) to subtract from the rounded
   * validity start period.
   */
  struct GNUNET_TIME_Relative start_offset;

  /**
   * Token family kind.
   */
  enum TALER_MERCHANTDB_TokenFamilyKind kind;

  /**
   * Counter for each issued token of this family.
   */
  uint64_t issued;

  /**
   * Counter for each used token of this family.
   */
  uint64_t used;
};


/**
 * Minimal product details for inventory templates.
 */
struct TALER_MERCHANTDB_InventoryProductDetails
{
  /**
   * Name of the product.
   */
  char *product_name;

  /**
   * Description of the product.
   */
  char *description;

  /**
   * Internationalized description.
   */
  json_t *description_i18n;

  /**
   * Unit in which the product is sold.
   */
  char *unit;

  /**
   * List of per-unit prices.
   */
  struct TALER_Amount *price_array;

  /**
   * Number of entries in @e price_array.
   */
  size_t price_array_length;

  /**
   * Hash of the product image data, or NULL.
   */
  char *image_hash;

  /**
   * Honor fractional stock if TRUE, else only integer stock.
   */
  bool allow_fractional_quantity;

  /**
   * Precision level (number of decimal places) to apply when
   * fractional quantities are enabled.
   */
  uint32_t fractional_precision_level;

  /**
   * Remaining units after sold/lost/locked deductions.
   */
  uint64_t remaining_stock;

  /**
   * Fractional part of remaining units in units of 1/1000000 of the base value.
   */
  uint32_t remaining_stock_frac;

  /**
   * List of taxes the merchant pays for this product. Never NULL,
   * but can be an empty array.
   */
  json_t *taxes;
};


/**
 * Details about an inventory measurement unit.
 */
struct TALER_MERCHANTDB_UnitDetails
{

  /**
   * Database serial.
   */
  uint64_t unit_serial;

  /**
   * Backend identifier used in product payloads.
   */
  char *unit;

  /**
   * Default long label (fallback string).
   */
  char *unit_name_long;

  /**
   * Default short label (fallback string).
   */
  char *unit_name_short;

  /**
   * Internationalised long labels.
   */
  json_t *unit_name_long_i18n;

  /**
   * Internationalised short labels.
   */
  json_t *unit_name_short_i18n;

  /**
   * Whether fractional quantities are enabled by default.
   */
  bool unit_allow_fraction;

  /**
   * Maximum number of fractional digits honoured by default.
   */
  uint32_t unit_precision_level;

  /**
   * Hidden from selectors when false.
   */
  bool unit_active;

  /**
   * Built-in units cannot be deleted.
   */
  bool unit_builtin;
};


/**
 * Details about a wire account of the merchant.
 */
struct TALER_MERCHANTDB_AccountDetails
{
  /**
   * Hash of the wire details (@e payto_uri and @e salt).
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * Salt value used for hashing @e payto_uri.
   */
  struct TALER_WireSaltP salt;

  /**
   * Instance ID. Do not free (may be aliased with
   * the instance ID given in the query!).
   * FIXME: set in all functions involving this struct!
   */
  const char *instance_id;

  /**
   * Actual account address as a payto://-URI.
   */
  struct TALER_FullPayto payto_uri;

  /**
   * Where can the taler-merchant-wirewatch helper
   * download information about incoming transfers?
   * NULL if not available.
   */
  char *credit_facade_url;

  /**
   * JSON with credentials to use to access the
   * @e credit_facade_url.
   */
  json_t *credit_facade_credentials;

  /**
   * Additional meta data to include in wire transfers to this
   * account. Can be NULL if not used.
   */
  char *extra_wire_subject_metadata;

  /**
   * Is the account set for active use in new contracts?
   */
  bool active;

};


/**
 * Binary login token. Just a vanilla token made out
 * of random bits.
 */
struct TALER_MERCHANTDB_LoginTokenP
{
  /**
   * 32 bytes of entropy.
   */
  uint64_t data[32 / 8];
};

/**
 * Authentication settings for an instance.
 */
struct TALER_MERCHANTDB_InstanceAuthSettings
{
  /**
   * Hash used for authentication.  All zero if authentication is off.
   */
  struct TALER_MerchantAuthenticationHashP auth_hash;

  /**
   * Salt used to hash the "Authentication" header, the result must then
   * match the @e auth_hash.
   */
  struct TALER_MerchantAuthenticationSaltP auth_salt;
};


/**
 * General settings for an instance.
 */
struct TALER_MERCHANTDB_InstanceSettings
{
  /**
   * prefix for the instance under "/instances/"
   */
  char *id;

  /**
   * legal name of the instance
   */
  char *name;

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

  /**
   * email contact for password reset / possibly admin / customers
   */
  char *email;

  /**
   * phone contact for password reset / possibly admin / customers
   */
  char *phone;

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

  /**
   * Address of the business
   */
  json_t *address;

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

  /**
   * Use STEFAN curves to determine acceptable
   * fees by default (otherwise: accept no fees by default).
   */
  bool use_stefan;

  /**
   * True of @e phone was validated.
   */
  bool phone_validated;

  /**
   * True of @e email was validated.
   */
  bool email_validated;

  /**
   * If the frontend does NOT specify an execution date, how long should
   * we tell the exchange to wait to aggregate transactions before
   * executing the wire transfer?  This delay is added to the current
   * time when we generate the advisory execution time for the exchange.
   */
  struct GNUNET_TIME_Relative default_wire_transfer_delay;

  /**
   * If the frontend does NOT specify a payment deadline, how long should
   * offers we make be valid by default?
   */
  struct GNUNET_TIME_Relative default_pay_delay;

  /**
   * If the frontend does NOT specify a refund deadline, how long should
   * refunds be possible?
   */
  struct GNUNET_TIME_Relative default_refund_delay;

  /**
   * How much should we round up the wire transfer deadline computed by
   * adding the @e default_wire_transfer_delay to the refund deadline.
   */
  enum GNUNET_TIME_RounderInterval default_wire_transfer_rounding_interval;

};


/**
 * Free members of @a pd, but not @a pd itself.
 *
 * @param[in] pd product details to clean up
 */
void
TALER_MERCHANTDB_product_details_free (
  struct TALER_MERCHANTDB_ProductDetails *pd);


/**
 * Free members of @a tp, but not @a tp itself.
 *
 * @param[in] tp template details to clean up
 */
void
TALER_MERCHANTDB_template_details_free (
  struct TALER_MERCHANTDB_TemplateDetails *tp);


/**
 * Free members of @a wb, but not @a wb itself.
 *
 * @param[in] wb webhook details to clean up
 */
void
TALER_MERCHANTDB_webhook_details_free (
  struct TALER_MERCHANTDB_WebhookDetails *wb);

/**
 * Free members of @a pwb, but not @a pwb itself.
 *
 * @param[in] pwb pending webhook details to clean up
 */
void
TALER_MERCHANTDB_pending_webhook_details_free (
  struct TALER_MERCHANTDB_PendingWebhookDetails *pwb);


/**
 * Free members of @a tf, but not @a tf itself.
 *
 * @param[in] tf token family details to clean up
 */
void
TALER_MERCHANTDB_token_family_details_free (
  struct TALER_MERCHANTDB_TokenFamilyDetails *tf);


/**
 * Free members of @a cd, but not @a cd itself.
 *
 * @param[in] cd token family details to clean up
 */
void
TALER_MERCHANTDB_category_details_free (
  struct TALER_MERCHANTDB_CategoryDetails *cd);

/**
 * Free members of @a ud, but not @a ud itself.
 *
 * @param[in] ud unit details to clean up
 */
void
TALER_MERCHANTDB_unit_details_free (
  struct TALER_MERCHANTDB_UnitDetails *ud);

#endif  /* MERCHANT_DB_H */

/* end of taler_merchantdb_lib.h */
