/*
  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 include/donaudb_plugin.h
 * @brief Low-level (statement-level) database access for the donau
 * @author Johannes Casaburi
 */
#ifndef DONAUDB_PLUGIN_H
#define DONAUDB_PLUGIN_H
// #include <jansson.h>
#include <gnunet/gnunet_db_lib.h>
#include <taler/taler_json_lib.h>
#include "donau_signatures.h"
#include "donau_util.h"

/**
 * Meta data about an donau signing key.
 */
struct DONAUDB_SignkeyMetaData
{
  /**
   * Start time of the validity period for this key.
   */
  struct GNUNET_TIME_Timestamp valid_from;

  /**
   * The donau will sign messages with this key between @e start and this time.
   */
  struct GNUNET_TIME_Timestamp expire_sign;

  /**
   * When do signatures with this sign key become invalid?
   * After this point, these signatures cannot be used in (legal)
   * disputes anymore, as the Donau is then allowed to destroy its side
   * of the evidence.  @e expire_legal is expected to be significantly
   * larger than @e expire_sign (by a year or more).
   */
  struct GNUNET_TIME_Timestamp expire_legal;

};

/**
 * Meta data about a charity.
 */
struct DONAUDB_CharityMetaData
{
  /**
   * Charity public key
   */
  struct DONAU_CharityPublicKeyP charity_pub;

  /**
   * Charity name
   */
  char *charity_name;

  /**
   * Charity url
   */
  char *charity_url;

  /**
   * Charity yearly donation limit
   */
  struct TALER_Amount max_per_year;

  /**
   * Charity donations received in the current year
   */
  struct TALER_Amount receipts_to_date;

  /**
   * Current year
   */
  uint32_t current_year;

};

/**
 * Meta data about issued receipts of a request.
 */
struct DONAUDB_IssuedReceiptsMetaData
{
  /**
   * Charity id
   */
  uint64_t charity_id;

  /**
   * total issued amount of the receipts
   */
  struct TALER_Amount amount;

  /**
   * number of signatures
   */
  size_t num_sig;

  /**
   * Array of blinded signatures
   */
  struct DONAU_BlindedDonationUnitSignature *blinded_sigs;

};

/**
 * @brief All information about a donation unit key.
 */
struct DONAUDB_DonationUnitKey
{
  /**
   * The private key of the donation unit.  Will be NULL if the private
   * key is not available.
   */
  struct DONAU_DonationUnitPublicKey donation_unit_priv;

  /**
   * Decoded donation unit public key.
   */
  struct DONAU_DonationUnitPublicKey donation_unit_pub;

};


/**
 * Signature of a function called with information about the donau's
 * signing keys.
 *
 * @param cls closure with a `struct DH_KeyStateHandle *`
 * @param donau_pub public key of the donau
 * @param meta meta data information about the signing type (expirations)
 */
typedef void
(*DONAUDB_IterateActiveSigningKeysCallback)(
  void *cls,
  const struct DONAU_DonauPublicKeyP *donau_pub,
  struct DONAUDB_SignkeyMetaData *meta);

/**
 * Return donation units.
 *
 * @param cls closure
 */
typedef enum GNUNET_GenericReturnValue
(*DONAUDB_IterateDonationUnitsCallback)(
  void *cls,
  const struct DONAU_DonationUnitHashP *h_donation_unit_pub,
  const struct DONAU_DonationUnitPublicKey *donation_unit_pub,
  uint64_t validity_year,
  struct TALER_Amount *value);


/**
 * Return charities.
 *
 * @param cls closure
 */
typedef enum GNUNET_GenericReturnValue
(*DONAUDB_GetCharitiesCallback)(
  void *cls,
  uint64_t charity_id,
  const struct DONAU_CharityPublicKeyP *charity_pub,
  const char *charity_name,
  const struct TALER_Amount *max_per_year,
  uint32_t current_year,
  const struct TALER_Amount *receipts_to_date);

/**
 * Return history.
 *
 * @param cls closure
 */
typedef enum GNUNET_GenericReturnValue
(*DONAUDB_GetHistoryCallback)(
  void *cls,
  unsigned long long charity_id,
  struct TALER_Amount final_amount,
  uint64_t donation_year);

/**
 * @brief The plugin API, returned from the plugin's "init" function.
 * The argument given to "init" is simply a configuration handle.
 */
struct DONAUDB_Plugin
{

  /**
   * Closure for all callbacks.
   */
  void *cls;

  /**
   * Name of the library which generated this plugin.  Set by the
   * plugin loader.
   */
  char *library_name;


  /**
   * Drop the Taler tables.  This should only be used in testcases.
   *
   * @param cls the @e cls of this struct with the plugin-specific state
   * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
   */
  enum GNUNET_GenericReturnValue
    (*drop_tables)(void *cls);

  /**
   * Create the necessary tables if they are not present
   *
   * @param cls the @e cls of this struct with the plugin-specific state
   * @param support_partitions true to enable partitioning support (disables foreign key constraints)
   * @param num_partitions number of partitions to create,
   *     (0 to not actually use partitions, 1 to only
   *      setup a default partition, >1 for real partitions)
   * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
   */
  enum GNUNET_GenericReturnValue
    (*create_tables)(void *cls);


  /**
   * Start a transaction.
   *
   * @param cls the @e cls of this struct with the plugin-specific state
   * @param name unique name identifying the transaction (for debugging),
   *             must point to a constant
   * @return #GNUNET_OK on success
   */
  enum GNUNET_GenericReturnValue
    (*start)(void *cls,
             const char *name);


  /**
   * Start a READ COMMITTED transaction.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   * @param name unique name identifying the transaction (for debugging)
   *             must point to a constant
   * @return #GNUNET_OK on success
   */
  enum GNUNET_GenericReturnValue
    (*start_read_committed)(void *cls,
                            const char *name);

  /**
   * Start a READ ONLY serializable transaction.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   * @param name unique name identifying the transaction (for debugging)
   *             must point to a constant
   * @return #GNUNET_OK on success
   */
  enum GNUNET_GenericReturnValue
    (*start_read_only)(void *cls,
                       const char *name);


  /**
   * Commit a transaction.
   *
   * @param cls the @e cls of this struct with the plugin-specific state
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*commit)(void *cls);


  /**
   * Do a pre-flight check that we are not in an uncommitted transaction.
   * If we are, try to commit the previous transaction and output a warning.
   * Does not return anything, as we will continue regardless of the outcome.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   * @return #GNUNET_OK if everything is fine
   *         #GNUNET_NO if a transaction was rolled back
   *         #GNUNET_SYSERR on hard errors
   */
  enum GNUNET_GenericReturnValue
    (*preflight)(void *cls);


  /**
   * Abort/rollback a transaction.
   *
   * @param cls the @e cls of this struct with the plugin-specific state
   */
  void
  (*rollback) (void *cls);


  /**
   * Function called to perform "garbage collection" on the
   * database, expiring records we no longer require.
   *
   * @param cls closure
   * @return #GNUNET_OK on success,
   *         #GNUNET_SYSERR on DB errors
   */
  enum GNUNET_GenericReturnValue
    (*gc)(void *cls);


  /**
   * Register callback to be invoked on events of type @a es.
   *
   * @param cls database context to use
   * @param timeout how long to wait at most
   * @param es specification of the event to listen for
   * @param cb function to call when the event happens, possibly
   *         multiple times (until cancel is invoked)
   * @param cb_cls closure for @a cb
   * @return handle useful to cancel the listener
   */
  struct GNUNET_DB_EventHandler *
  (*event_listen)(void *cls,
                  struct GNUNET_TIME_Relative timeout,
                  const struct GNUNET_DB_EventHeaderP *es,
                  GNUNET_DB_EventCallback cb,
                  void *cb_cls);

  /**
   * Stop notifications.
   *
   * @param cls database context to use
   * @param eh handle to unregister.
   */
  void
  (*event_listen_cancel)(void *cls,
                         struct GNUNET_DB_EventHandler *eh);


  /**
   * Notify all that listen on @a es of an event.
   *
   * @param cls database context to use
   * @param es specification of the event to generate
   * @param extra additional event data provided
   * @param extra_size number of bytes in @a extra
   */
  void
  (*event_notify)(void *cls,
                  const struct GNUNET_DB_EventHeaderP *es,
                  const void *extra,
                  size_t extra_size);

  /**
   * Get charity.
   *
   * @param cls closure
   * @param charity_id
   * @param meta
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_charity)(
    void *cls,
    uint64_t charity_id,
    struct DONAUDB_CharityMetaData *meta);

  /**
   * Delete charity.
   *
   * @param cls closure
   * @param charity_id
   * @param[out] found set to true if the purse was found
   *        (if false, purse could not be deleted)
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*do_charity_delete)(
    void *cls,
    uint64_t charity_id);

  /**
   * Get charities.
   *
   * @param cls closure
   * @param cb callback to invoke on each match
   * @param cb_cls closure for @a cb
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*get_charities)(
    void *cls,
    DONAUDB_GetCharitiesCallback cb,
    void *cb_cls);


  /**
   * Insert Charity
   *
   * @param cls closure
   * @param charity_pub charity public key
   * @param charity_name name of the charity
   * @param charity_url Web site fo the charity
   * @param max_per_year yearly donation limit
   * @param[out] charity_id set to unique ID assigned to this charity,
   *    set to 0 on conflict (@a charity_pub exists, but with different data)
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_charity)(
    void *cls,
    const struct DONAU_CharityPublicKeyP *charity_pub,
    const char *charity_name,
    const char *charity_url,
    const struct TALER_Amount *max_per_year,
    uint64_t *charity_id);


  /**
   * Update existing charity meta data.
   *
   * @param cls closure
   * @param charity_id identifier of the charity to update
   * @param charity_pub new public key
   * @param charity_name new human-readable name
   * @param charity_url new URL of the charity
   * @param max_per_year new yearly donation cap
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*update_charity)(
    void *cls,
    uint64_t charity_id,
    const struct DONAU_CharityPublicKeyP *charity_pub,
    const char *charity_name,
    const char *charity_url,
    const struct TALER_Amount *max_per_year);


  /**
   * Iterate donation units.
   *
   * @param cls closure
   * @param cb callback to invoke on each match
   * @param cb_cls closure for @a cb
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*iterate_donation_units)(
    void *cls,
    DONAUDB_IterateDonationUnitsCallback cb,
    void *cb_cls);

  /**
    * Get history.
    *
    * @param cls closure
    * @param cb callback to invoke on each match
    * @param cb_cls closure for @a cb
    * @return database transaction status
    */
  enum GNUNET_DB_QueryStatus
    (*get_history)(
    void *cls,
    DONAUDB_GetHistoryCallback cb,
    void *cb_cls);

  /**
    * Lookup history entry.
    *
    * @param cls closure
    * @param cb callback to invoke on each match
    * @param cb_cls closure for @a cb
    * @return database transaction status
    */
  enum GNUNET_DB_QueryStatus
    (*lookup_history_entry)(
    void *cls,
    const unsigned long long charity_id,
    const struct TALER_Amount *final_amount,
    const uint64_t donation_year);

  /**
    * Insert donation_unit.
    *
    * @param cls closure
    * @param donation_unit_pub
    * @return database transaction status
    */
  enum GNUNET_DB_QueryStatus
    (*insert_donation_unit)(
    void *cls,
    const struct DONAU_DonationUnitHashP *h_donation_unit_pub,
    const struct DONAU_DonationUnitPublicKey *donation_unit_pub,
    const uint64_t validity_year,
    const struct TALER_Amount *value);

  /**
    * Insert history entry of a charity
    *
    * @param cls closure
    * @param charity_id charity id
    * @param final_amount final donation amount at the end of the donation year
    * @param donation_year year of the donations
    * @return transaction status code
    */
  enum GNUNET_DB_QueryStatus
    (*insert_history_entry)(
    void *cls,
    const uint64_t charity_id,
    const struct TALER_Amount *final_amount,
    const uint64_t donation_year);

  /**
    * Insert issued blinded donation receipt to the charity.
    *
    * @param cls closure
    * @param num_blinded_sig
    * @param signatures blinded signatures
    * @param charity_id identifier of the charity
    * @param h_receipt hash of the donation receipt
    * @param amount_receipts_request donation amount
    * @param smaller_than_max_per_year new receipts to day smaller than the max?
    * @return transaction status code
    */
  enum GNUNET_DB_QueryStatus
    (*insert_issued_receipt)(
    void *cls,
    const size_t num_blinded_sig,
    const struct DONAU_BlindedDonationUnitSignature signatures[num_blinded_sig],
    const uint64_t charity_id,
    const struct DONAU_DonationReceiptHashP *h_receipt,
    const struct TALER_Amount *amount_receipts_request,
    bool *smaller_than_max_per_year);

  /**
    * Insert submitted donation receipt from the donor.
    *
    * @param cls closure
    * @param h_donor_tax_id salted hash of the donors tax number
    * @param nonce nonce that is part of the unique donation identifier
    * @param donation_unit_pub donation unit public key
    * @param donau_sig donau signature in case the sign keys changed
    * @param donation_year year of the donation
    * @return transaction status code
    */
  enum GNUNET_DB_QueryStatus
    (*insert_submitted_receipts)(
    void *cls,
    struct DONAU_HashDonorTaxId *h_donor_tax_id,
    size_t num_dr,
    const struct DONAU_DonationReceipt donation_receipts[static num_dr],
    uint64_t donation_year);

  /**
   * Iterate submitted donation receipt.
   *
   * @param cls closure
   * @param value
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*iterate_submitted_receipts)(
    void *cls,
    const uint64_t donation_year,
    const struct DONAU_HashDonorTaxId *h_donor_tax_id,
    struct TALER_Amount *total_donations);

  /**
   * Lookup amount of the donation unit hash.
   *
   * @param cls closure
   * @param h_donation_unit_pub the hash over the donation unit public key
   * @param value the amount of the donation unit
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_donation_unit_amount)(
    void *cls,
    const struct DONAU_DonationUnitHashP *h_donation_unit_pub,
    struct TALER_Amount *value);

  /**
   * Lookup issued receipts from the charity.
   *
   * @param cls closure
   * @param h_receipts the hash over the blinded unique identifiers
   * @param meta meta data about an issued request
   * @return transaction status code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_issued_receipts)(
    void *cls,
    struct DONAU_DonationReceiptHashP *h_receitps,
    struct DONAUDB_IssuedReceiptsMetaData *meta);

  /**
    * Add signing key.
    *
    * @param cls closure
    * @param donau_pub the donau online signing public key
    * @param meta meta data about @a donau_pub
    * @return transaction status code
    */
  enum GNUNET_DB_QueryStatus
    (*insert_signing_key)(
    void *cls,
    const struct DONAU_DonauPublicKeyP *donau_pub,
    struct DONAUDB_SignkeyMetaData *meta);

  /**
    * Lookup signing key meta data.
    *
    * @param cls closure
    * @param donau_pub the donau signing public key
    * @param[out] meta meta data about @a donau_pub
    * @return transaction status code
    */
  enum GNUNET_DB_QueryStatus
    (*lookup_signing_key)(
    void *cls,
    const struct DONAU_DonauPublicKeyP *donau_pub,
    struct DONAUDB_SignkeyMetaData *meta);

  /**
    * Iterate donau signing keys.
    *
    * @param cls closure
    * @param cb callback to invoke on each match
    * @param cb_cls closure for @a cb
    * @return database transaction status
    */
  enum GNUNET_DB_QueryStatus
    (*iterate_active_signing_keys)(
    void *cls,
    DONAUDB_IterateActiveSigningKeysCallback cb,
    void *cb_cls);

};

#endif
