/*
   This file is part of TALER
   Copyright (C) 2022 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 iterate_records_by_table.h
 * @brief implementation of the lookup_records_by_table function
 * @author Christian Grothoff
 */
#ifndef EXCHANGE_DATABASE_ITERATE_RECORDS_BY_TABLE_H
#define EXCHANGE_DATABASE_ITERATE_RECORDS_BY_TABLE_H

#include "taler/taler_json_lib.h"
#include "exchangedb_lib.h"


/**
 * Enumeration of all of the tables replicated by exchange-auditor
 * database replication.
 *
 * Note: wire_accounts is not replicated. So far not needed by the auditor.
 */
enum TALER_EXCHANGEDB_ReplicatedTable
{
  TALER_EXCHANGEDB_RT_DENOMINATIONS,
  TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS,
  TALER_EXCHANGEDB_RT_KYC_TARGETS,
  TALER_EXCHANGEDB_RT_WIRE_TARGETS,
  TALER_EXCHANGEDB_RT_RESERVES,
  TALER_EXCHANGEDB_RT_RESERVES_IN,
  TALER_EXCHANGEDB_RT_RESERVES_CLOSE,
  TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS,
  TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS,
  TALER_EXCHANGEDB_RT_AUDITORS,
  TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS,
  TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS,
  TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS,
  TALER_EXCHANGEDB_RT_KNOWN_COINS,
  TALER_EXCHANGEDB_RT_REFRESH,
  TALER_EXCHANGEDB_RT_BATCH_DEPOSITS,
  TALER_EXCHANGEDB_RT_COIN_DEPOSITS,
  TALER_EXCHANGEDB_RT_REFUNDS,
  TALER_EXCHANGEDB_RT_WIRE_OUT,
  TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING,
  TALER_EXCHANGEDB_RT_AGGREGATION_DEFERRALS,
  TALER_EXCHANGEDB_RT_WIRE_FEE,
  TALER_EXCHANGEDB_RT_GLOBAL_FEE,
  TALER_EXCHANGEDB_RT_RECOUP,
  TALER_EXCHANGEDB_RT_RECOUP_REFRESH,
  TALER_EXCHANGEDB_RT_PURSE_REQUESTS,
  TALER_EXCHANGEDB_RT_PURSE_DECISION,
  TALER_EXCHANGEDB_RT_PURSE_MERGES,
  TALER_EXCHANGEDB_RT_PURSE_DEPOSITS,
  TALER_EXCHANGEDB_RT_ACCOUNT_MERGES,
  TALER_EXCHANGEDB_RT_HISTORY_REQUESTS,
  TALER_EXCHANGEDB_RT_CLOSE_REQUESTS,
  TALER_EXCHANGEDB_RT_WADS_OUT,
  TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES,
  TALER_EXCHANGEDB_RT_WADS_IN,
  TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES,
  TALER_EXCHANGEDB_RT_PROFIT_DRAINS,
  TALER_EXCHANGEDB_RT_AML_STAFF,
  TALER_EXCHANGEDB_RT_PURSE_DELETION,
  TALER_EXCHANGEDB_RT_WITHDRAW,
  TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES,
  TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES,
  TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES,
  TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES,
  TALER_EXCHANGEDB_RT_AML_HISTORY,
  TALER_EXCHANGEDB_RT_KYC_EVENTS,
  TALER_EXCHANGEDB_RT_KYCAUTHS_IN
};


/**
 * Record of a single entry in a replicated table.
 */
struct TALER_EXCHANGEDB_TableData
{
  /**
   * Data of which table is returned here?
   */
  enum TALER_EXCHANGEDB_ReplicatedTable table;

  /**
   * Serial number of the record.
   */
  uint64_t serial;

  /**
   * Table-specific details.
   */
  union
  {

    /**
     * Details from the 'denominations' table.
     */
    struct
    {
      uint32_t denom_type;
      uint32_t age_mask;
      struct TALER_DenominationPublicKey denom_pub;
      struct TALER_MasterSignatureP master_sig;
      struct GNUNET_TIME_Timestamp valid_from;
      struct GNUNET_TIME_Timestamp expire_withdraw;
      struct GNUNET_TIME_Timestamp expire_deposit;
      struct GNUNET_TIME_Timestamp expire_legal;
      struct TALER_Amount coin;
      struct TALER_DenomFeeSet fees;
    } denominations;

    struct
    {
      struct TALER_MasterSignatureP master_sig;
      uint64_t denominations_serial;
    } denomination_revocations;

    struct
    {
      struct TALER_FullPayto full_payto_uri;
    } wire_targets;

    struct
    {
      struct TALER_NormalizedPaytoHashP h_normalized_payto;
      struct TALER_AccountAccessTokenP access_token;
      union TALER_AccountPublicKeyP target_pub;
      bool no_account;
      bool is_wallet;
    } kyc_targets;

    struct
    {
      struct TALER_AccountAccessTokenP target_token;
      /* absolute, not a timestamp: do_trigger_kyc_rule_for_account.c
         writes this column with microsecond precision (whereas
         insert_active_legitimization_measure.c rounds to seconds) */
      struct GNUNET_TIME_Absolute start_time;
      json_t *measures;
      uint32_t display_priority;
    } legitimization_measures;

    struct
    {
      struct TALER_NormalizedPaytoHashP h_payto;
      struct GNUNET_TIME_Timestamp decision_time;
      struct GNUNET_TIME_Timestamp expiration_time;
      json_t *properties;
      bool to_investigate;
      json_t *new_rules;
    } legitimization_outcomes;

    struct
    {
      struct TALER_NormalizedPaytoHashP h_payto;
      /* absolute, not a timestamp: the exchange stores this column with
         microsecond precision (see insert_legitimization_process.c) */
      struct GNUNET_TIME_Absolute start_time;
      struct GNUNET_TIME_Timestamp expiration_time;
      uint64_t legitimization_measure_serial_id;
      uint32_t measure_index;
      char *provider_name;
      char *provider_user_id;
      char *provider_legitimization_id;
      char *redirect_url;
    } legitimization_processes;

    struct
    {
      struct TALER_NormalizedPaytoHashP h_payto;
      uint64_t legitimization_serial;
      struct GNUNET_TIME_Timestamp collection_time;
      struct GNUNET_TIME_Timestamp expiration_time;
      char *form_name; /**< NULL if the attributes came from a provider */
      bool by_aml_officer;
      void *encrypted_attributes;
      size_t encrypted_attributes_size;
    } kyc_attributes;

    struct
    {
      struct TALER_NormalizedPaytoHashP h_payto;
      uint64_t outcome_serial_id;
      char *justification;
      struct TALER_AmlOfficerPublicKeyP decider_pub;
      struct TALER_AmlOfficerSignatureP decider_sig;
      /* both NULL/0 unless the AML officer attached attributes to the
         decision (see insert_aml_decision.sql) */
      struct GNUNET_HashCode kyc_attributes_hash;
      bool no_kyc_attributes_hash;
      uint64_t kyc_attributes_serial_id;
      bool no_kyc_attributes_serial_id;
    } aml_history;

    struct
    {
      struct GNUNET_TIME_Timestamp event_timestamp;
      char *event_type;
    } kyc_events;

    struct
    {
      struct TALER_AmlOfficerPublicKeyP decider_pub;
      struct TALER_MasterSignatureP master_sig;
      char *decider_name;
      bool is_active;
      bool read_only;
      struct GNUNET_TIME_Timestamp last_change;
    } aml_staff;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct GNUNET_TIME_Timestamp expiration_date;
      struct GNUNET_TIME_Timestamp gc_date;
    } reserves;

    struct
    {
      uint64_t wire_reference;
      struct TALER_Amount credit;
      struct TALER_FullPaytoHashP sender_account_h_payto;
      char *exchange_account_section;
      struct GNUNET_TIME_Timestamp execution_date;
      struct TALER_ReservePublicKeyP reserve_pub;
    } reserves_in;

    struct
    {
      uint64_t wire_reference;
      struct TALER_Amount credit;
      struct TALER_FullPaytoHashP sender_account_h_payto;
      char *exchange_account_section;
      struct GNUNET_TIME_Timestamp execution_date;
      union TALER_AccountPublicKeyP account_pub;
    } kycauth_in;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct GNUNET_TIME_Timestamp request_timestamp;
      struct GNUNET_TIME_Timestamp expiration_date;
      struct TALER_ReserveSignatureP reserve_sig;
      struct TALER_Amount reserve_payment;
      uint32_t requested_purse_limit;
    } reserves_open_requests;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_CoinSpendPublicKeyP coin_pub;
      struct TALER_CoinSpendSignatureP coin_sig;
      struct TALER_ReserveSignatureP reserve_sig;
      struct TALER_Amount contribution;
    } reserves_open_deposits;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct GNUNET_TIME_Timestamp execution_date;
      struct TALER_WireTransferIdentifierRawP wtid;
      struct TALER_FullPaytoHashP sender_account_h_payto;
      struct TALER_Amount amount;
      struct TALER_Amount closing_fee;
    } reserves_close;

    struct
    {
      struct TALER_AuditorPublicKeyP auditor_pub;
      char *auditor_url;
      char *auditor_name;
      bool is_active;
      struct GNUNET_TIME_Timestamp last_change;
    } auditors;

    struct
    {
      uint64_t auditor_uuid;
      uint64_t denominations_serial;
      struct TALER_AuditorSignatureP auditor_sig;
    } auditor_denom_sigs;

    struct
    {
      struct TALER_ExchangePublicKeyP exchange_pub;
      struct TALER_MasterSignatureP master_sig;
      struct TALER_EXCHANGEDB_SignkeyMetaData meta;
    } exchange_sign_keys;

    struct
    {
      uint64_t esk_serial;
      struct TALER_MasterSignatureP master_sig;
    } signkey_revocations;

    struct
    {
      struct TALER_CoinSpendPublicKeyP coin_pub;
      struct TALER_AgeCommitmentHashP age_hash;
      uint64_t denominations_serial;
      struct TALER_DenominationSignature denom_sig;
    } known_coins;

    struct
    {
      struct TALER_RefreshCommitmentP rc;
      struct GNUNET_TIME_Timestamp execution_date;
      struct TALER_Amount amount_with_fee;
      struct TALER_CoinSpendPublicKeyP old_coin_pub;
      struct TALER_CoinSpendSignatureP old_coin_sig;
      struct TALER_PublicRefreshMasterSeedP refresh_seed;
      uint32_t noreveal_index;
      struct TALER_HashBlindedPlanchetsP planchets_h;
      struct TALER_HashBlindedPlanchetsP selected_h;
      bool no_blinding_seed;
      struct TALER_BlindingMasterSeedP blinding_seed;
      size_t num_cs_r_values;
      struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_values;
      uint64_t cs_r_choices;
      size_t num_coins;
      uint64_t *denom_serials;
      struct TALER_BlindedDenominationSignature *denom_sigs;
    } refresh;

    struct
    {
      uint64_t shard;
      struct TALER_MerchantPublicKeyP merchant_pub;
      struct GNUNET_TIME_Timestamp wallet_timestamp;
      struct GNUNET_TIME_Timestamp exchange_timestamp;
      struct GNUNET_TIME_Timestamp refund_deadline;
      struct GNUNET_TIME_Timestamp wire_deadline;
      struct TALER_PrivateContractHashP h_contract_terms;
      bool no_wallet_data_hash;
      struct GNUNET_HashCode wallet_data_hash;
      struct TALER_WireSaltP wire_salt;
      struct TALER_FullPaytoHashP wire_target_h_payto;
      struct TALER_Amount total_amount;
      struct TALER_Amount total_without_fee;
      struct TALER_MerchantSignatureP merchant_sig;
      bool done;
    } batch_deposits;

    struct
    {
      uint64_t batch_deposit_serial_id;
      struct TALER_CoinSpendPublicKeyP coin_pub;
      struct TALER_CoinSpendSignatureP coin_sig;
      struct TALER_Amount amount_with_fee;
    } coin_deposits;

    struct
    {
      struct TALER_CoinSpendPublicKeyP coin_pub;
      uint64_t batch_deposit_serial_id;
      struct TALER_MerchantSignatureP merchant_sig;
      uint64_t rtransaction_id;
      struct TALER_Amount amount_with_fee;
    } refunds;

    struct
    {
      struct GNUNET_TIME_Timestamp execution_date;
      struct TALER_WireTransferIdentifierRawP wtid_raw;
      struct TALER_FullPaytoHashP wire_target_h_payto;
      char *exchange_account_section;
      struct TALER_Amount amount;
    } wire_out;

    struct
    {
      uint64_t batch_deposit_serial_id;
      struct TALER_WireTransferIdentifierRawP wtid_raw;
    } aggregation_tracking;

    struct
    {
      uint64_t batch_deposit_serial_id;
      struct TALER_WireTransferIdentifierRawP wtid_raw;
      struct TALER_FullPaytoHashP wire_target_h_payto;
      struct TALER_Amount amount;
      uint32_t deferral_reason;
      uint64_t legitimization_requirement_serial_id;
      struct GNUNET_TIME_Timestamp deferral_time;
    } aggregation_deferrals;

    struct
    {
      char *wire_method;
      struct GNUNET_TIME_Timestamp start_date;
      struct GNUNET_TIME_Timestamp end_date;
      struct TALER_WireFeeSet fees;
      struct TALER_MasterSignatureP master_sig;
    } wire_fee;

    struct
    {
      struct GNUNET_TIME_Timestamp start_date;
      struct GNUNET_TIME_Timestamp end_date;
      struct TALER_GlobalFeeSet fees;
      struct GNUNET_TIME_Relative purse_timeout;
      struct GNUNET_TIME_Relative history_expiration;
      uint32_t purse_account_limit;
      struct TALER_MasterSignatureP master_sig;
    } global_fee;

    struct
    {
      struct TALER_CoinSpendPublicKeyP coin_pub;
      struct TALER_CoinSpendSignatureP coin_sig;
      union GNUNET_CRYPTO_BlindingSecretP coin_blind;
      struct TALER_Amount amount;
      struct GNUNET_TIME_Timestamp timestamp;
      uint64_t withdraw_serial_id;
    } recoup;

    struct
    {
      uint64_t known_coin_id;
      struct TALER_CoinSpendPublicKeyP coin_pub;
      struct TALER_CoinSpendSignatureP coin_sig;
      union GNUNET_CRYPTO_BlindingSecretP coin_blind;
      struct TALER_Amount amount;
      struct GNUNET_TIME_Timestamp recoup_timestamp;
      uint64_t refresh_id;
    } recoup_refresh;

    struct
    {
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_PurseMergePublicKeyP merge_pub;
      struct GNUNET_TIME_Timestamp purse_creation;
      struct GNUNET_TIME_Timestamp purse_expiration;
      struct TALER_PrivateContractHashP h_contract_terms;
      uint32_t age_limit;
      uint32_t flags;
      struct TALER_Amount amount_with_fee;
      struct TALER_Amount purse_fee;
      struct TALER_PurseContractSignatureP purse_sig;
    } purse_requests;

    struct
    {
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct GNUNET_TIME_Timestamp action_timestamp;
      bool refunded;
    } purse_decision;

    struct
    {
      uint64_t partner_serial_id;
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_PurseMergeSignatureP merge_sig;
      struct GNUNET_TIME_Timestamp merge_timestamp;
    } purse_merges;

    struct
    {
      uint64_t partner_serial_id;
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_CoinSpendPublicKeyP coin_pub;
      struct TALER_Amount amount_with_fee;
      struct TALER_CoinSpendSignatureP coin_sig;
    } purse_deposits;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_ReserveSignatureP reserve_sig;
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_NormalizedPaytoHashP wallet_h_payto;
    } account_merges;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_ReserveSignatureP reserve_sig;
      struct GNUNET_TIME_Timestamp request_timestamp;
      struct TALER_Amount history_fee;
    } history_requests;

    struct
    {
      struct TALER_ReservePublicKeyP reserve_pub;
      struct GNUNET_TIME_Timestamp close_timestamp;
      struct TALER_ReserveSignatureP reserve_sig;
      struct TALER_Amount close;
      struct TALER_Amount close_fee;
      struct TALER_FullPayto payto_uri;
    } close_requests;

    struct
    {
      struct TALER_WadIdentifierP wad_id;
      uint64_t partner_serial_id;
      struct TALER_Amount amount;
      struct GNUNET_TIME_Timestamp execution_time;
    } wads_out;

    struct
    {
      uint64_t wad_out_serial_id;
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_PrivateContractHashP h_contract;
      struct GNUNET_TIME_Timestamp purse_expiration;
      struct GNUNET_TIME_Timestamp merge_timestamp;
      struct TALER_Amount amount_with_fee;
      struct TALER_Amount wad_fee;
      struct TALER_Amount deposit_fees;
      struct TALER_ReserveSignatureP reserve_sig;
      struct TALER_PurseContractSignatureP purse_sig;
    } wads_out_entries;

    struct
    {
      struct TALER_WadIdentifierP wad_id;
      char *origin_exchange_url;
      struct TALER_Amount amount;
      struct GNUNET_TIME_Timestamp arrival_time;
    } wads_in;

    struct
    {
      uint64_t wad_in_serial_id;
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_PrivateContractHashP h_contract;
      struct GNUNET_TIME_Timestamp purse_expiration;
      struct GNUNET_TIME_Timestamp merge_timestamp;
      struct TALER_Amount amount_with_fee;
      struct TALER_Amount wad_fee;
      struct TALER_Amount deposit_fees;
      struct TALER_ReserveSignatureP reserve_sig;
      struct TALER_PurseContractSignatureP purse_sig;
    } wads_in_entries;

    struct
    {
      struct TALER_WireTransferIdentifierRawP wtid;
      char *account_section;
      struct TALER_FullPayto payto_uri;
      struct GNUNET_TIME_Timestamp trigger_date;
      struct TALER_Amount amount;
      struct TALER_MasterSignatureP master_sig;
    } profit_drains;

    struct
    {
      struct TALER_PurseContractPublicKeyP purse_pub;
      struct TALER_PurseContractSignatureP purse_sig;
    } purse_deletion;

    struct
    {
      struct TALER_HashBlindedPlanchetsP planchets_h;
      struct GNUNET_TIME_Timestamp execution_date;
      struct TALER_Amount amount_with_fee;
      struct TALER_ReservePublicKeyP reserve_pub;
      struct TALER_ReserveSignatureP reserve_sig;
      bool age_proof_required;
      uint16_t max_age;
      uint16_t noreveal_index;
      struct TALER_HashBlindedPlanchetsP selected_h;
      bool no_blinding_seed;
      struct TALER_BlindingMasterSeedP blinding_seed;
      size_t num_cs_r_values;
      struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_values;
      uint64_t cs_r_choices;
      size_t num_coins;
      uint64_t *denom_serials;
      struct TALER_BlindedDenominationSignature *denom_sigs;
    } withdraw;

  } details;

};


/**
 * Function called on data to replicate in the auditor's database.
 *
 * @param cls closure
 * @param td record from an exchange table
 * @return #GNUNET_OK to continue to iterate,
 *         #GNUNET_SYSERR to fail with an error
 */
#ifndef TALER_EXCHANGEDB_REPLICATION_RESULT_CLOSURE
/**
 * Type of the closure for #TALER_EXCHANGEDB_ReplicationCallback.
 */
#define TALER_EXCHANGEDB_REPLICATION_RESULT_CLOSURE void
#endif
typedef int
(*TALER_EXCHANGEDB_ReplicationCallback)(
  TALER_EXCHANGEDB_REPLICATION_RESULT_CLOSURE *cls,
  const struct TALER_EXCHANGEDB_TableData *td);


/**
 * Function called on data to replicate in the auditor's database.
 *
 * @param cls closure
 * @param td record from an exchange table
 * @return #GNUNET_OK to continue to iterate,
 *         #GNUNET_SYSERR to fail with an error
 */
typedef int
(*TALER_EXCHANGEDB_ReplicationCallback)(
  TALER_EXCHANGEDB_REPLICATION_RESULT_CLOSURE *cls,
  const struct TALER_EXCHANGEDB_TableData *td);


/**
 * Lookup records above @a serial number in @a table. Used in
 * exchange-auditor database replication.
 *
 * @param pg the database context
 * @param table table for which we should return the serial
 * @param serial largest serial number to exclude
 * @param cb function to call on the records
 * @param cb_cls closure for @a cb
 * @return transaction status code, GNUNET_DB_STATUS_HARD_ERROR if
 *         @a table does not have a serial number
 */
enum GNUNET_DB_QueryStatus
TALER_EXCHANGEDB_iterate_records_by_table (
  struct TALER_EXCHANGEDB_PostgresContext *pg,
  enum TALER_EXCHANGEDB_ReplicatedTable table,
  uint64_t serial,
  TALER_EXCHANGEDB_ReplicationCallback cb,
  TALER_EXCHANGEDB_REPLICATION_RESULT_CLOSURE *cb_cls);


#endif
