/*
  This file is part of TALER
  Copyright (C) 2016 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/auditordb_lib.h
 * @brief high-level interface for the auditor's database
 * @author Florian Dold
 * @author Benedikt Mueller
 * @author Christian Grothoff
 */
#ifndef TALER_AUDITORDB_LIB_H
#define TALER_AUDITORDB_LIB_H

#include <jansson.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_db_lib.h>
#include <taler/taler_util.h>
#include <auditordb_lib.h>

/**
 * Connection to the postgres database of the auditor.
 */
struct TALER_AUDITORDB_PostgresContext;


/**
 * Information about a deposit confirmation we received from
 * a merchant.
 */
struct TALER_AUDITORDB_DepositConfirmation
{

  /**
   * Hash over the contract for which this deposit is made.
   */
  struct TALER_PrivateContractHashP h_contract_terms;

  /**
   * Hash over the policy extension for the deposit.
   */
  struct TALER_ExtensionPolicyHashP h_policy;

  /**
   * Hash over the wiring information of the merchant.
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * Time when this deposit confirmation was generated by the exchange.
   */
  struct GNUNET_TIME_Timestamp exchange_timestamp;

  /**
   * How much time does the @e merchant have to issue a refund
   * request?  Zero if refunds are not allowed.  After this time, the
   * coin cannot be refunded.  Note that the wire transfer will not be
   * performed by the exchange until the refund deadline.  This value
   * is taken from the original deposit request.
   */
  struct GNUNET_TIME_Timestamp refund_deadline;

  /**
   * How much time does the @e exchange have to wire the funds?
   */
  struct GNUNET_TIME_Timestamp wire_deadline;

  /**
   * Amount to be deposited, excluding fee.  Calculated from the
   * amount with fee and the fee from the deposit request.
   */
  struct TALER_Amount total_without_fee;

  /**
   * Array of the coin public keys involved in the
   * batch deposit operation.
   */
  const struct TALER_CoinSpendPublicKeyP *coin_pubs;

  /**
   * Array of coin deposit signatures from the deposit operation.
   */
  const struct TALER_CoinSpendSignatureP *coin_sigs;

  /**
   * The Merchant's public key.  Allows the merchant to later refund
   * the transaction or to inquire about the wire transfer identifier.
   */
  struct TALER_MerchantPublicKeyP merchant;

  /**
   * Signature from the exchange of type
   * #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT.
   */
  struct TALER_ExchangeSignatureP exchange_sig;

  /**
   * Public signing key from the exchange matching @e exchange_sig.
   */
  struct TALER_ExchangePublicKeyP exchange_pub;

  /**
   * Exchange master signature over @e exchange_sig.
   */
  struct TALER_MasterSignatureP master_sig;

  /**
   * Row of this entry in the auditor database.
   */
  uint64_t row_id;

  /**
   * Length of the @e coin_pubs and @e coin_sigs arrays.
   */
  unsigned int num_coins;

  bool suppressed;

};


/**
 * Information about a row inconsistency
 */
struct TALER_AUDITORDB_Generic_Update
{
  uint64_t row_id;
  bool suppressed;
  bool ancient;
};


/**
 * Information about a coin inconsistency
 */
struct TALER_AUDITORDB_CoinInconsistency
{
  uint64_t row_id;
  char *operation;
  struct TALER_Amount exchange_amount;
  struct TALER_Amount auditor_amount;
  struct GNUNET_CRYPTO_EddsaPublicKey coin_pub;
  bool profitable;
};

/**
 * Information about a row inconsistency
 */
struct TALER_AUDITORDB_RowInconsistency
{
  uint64_t row_id;
  char *row_table;
  char *diagnostic;
  bool suppressed;
};

/**
 * Information about a bad sig loss
 */
struct TALER_AUDITORDB_BadSigLosses
{
  uint64_t row_id;
  uint64_t problem_row_id;
  char *operation;
  struct TALER_Amount loss;
  struct GNUNET_CRYPTO_EddsaPublicKey operation_specific_pub;
  bool suppressed;
};

/**
 * Information about a closure lags
 */
struct TALER_AUDITORDB_ClosureLags
{
  uint64_t row_id;
  uint64_t problem_row_id;
  struct TALER_Amount amount;
  struct GNUNET_TIME_Absolute deadline;
  struct TALER_WireTransferIdentifierRawP wtid;
  struct TALER_FullPayto account;
  bool suppressed;
};

/**
 * Information about a emergency
 */
struct TALER_AUDITORDB_Emergency
{
  uint64_t row_id;
  struct TALER_DenominationHashP denompub_h;
  struct TALER_Amount denom_risk;
  struct TALER_Amount denom_loss;
  struct GNUNET_TIME_Absolute deposit_start;
  struct GNUNET_TIME_Absolute deposit_end;
  struct TALER_Amount value;
  bool suppressed;
};

/**
 * Information about an emergency by count
 */
struct TALER_AUDITORDB_EmergenciesByCount
{
  uint64_t row_id;
  struct TALER_DenominationHashP denompub_h;
  uint64_t num_issued;
  uint64_t num_known;
  struct TALER_Amount risk;
  struct GNUNET_TIME_Absolute start;
  struct GNUNET_TIME_Absolute deposit_end;
  struct TALER_Amount value;
  bool suppressed;
};

/**
 * Information about a fee time inconsistency
 */
struct TALER_AUDITORDB_FeeTimeInconsistency
{
  uint64_t row_id;
  uint64_t problem_row_id;
  char *type;
  struct GNUNET_TIME_Absolute time;
  char *diagnostic;
};

/**
 * Information about a denom key validity withdraw inconsistency
 */
struct TALER_AUDITORDB_DenominationKeyValidityWithdrawInconsistency
{
  uint64_t row_id;
  uint64_t problem_row_id;
  struct GNUNET_TIME_Absolute execution_date;
  struct TALER_ReservePublicKeyP reserve_pub;
  struct TALER_DenominationHashP denompub_h;
  bool suppressed;
};

/**
 * Information about a purse not closed inconsistencies
 */
struct TALER_AUDITORDB_PurseNotClosedInconsistencies
{
  uint64_t row_id;
  struct GNUNET_CRYPTO_EddsaPublicKey purse_pub;
  struct TALER_Amount amount;
  struct GNUNET_TIME_Absolute expiration_date;
  bool suppressed;
};

/**
 * Information about a reserve balance insufficient inconsistency
 */
struct TALER_AUDITORDB_ReserveBalanceInsufficientInconsistency
{
  uint64_t row_id;
  struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
  bool inconsistency_gain;
  struct TALER_Amount inconsistency_amount;
  bool suppressed;
};

/**
 * Information about a reserve in inconsistency
 */
struct TALER_AUDITORDB_ReserveInInconsistency
{
  uint64_t serial_id;
  uint64_t bank_row_id;
  struct TALER_Amount amount_exchange_expected;
  struct TALER_Amount amount_wired;
  struct TALER_ReservePublicKeyP reserve_pub;
  struct GNUNET_TIME_Absolute timestamp;
  struct TALER_FullPayto account;
  char *diagnostic;
  bool suppressed;

};

/**
 * Information about a disagreement between the bank and the exchange
 * about an incoming wire transfer that established an account key for
 * KYC authentication.
 */
struct TALER_AUDITORDB_KycauthInInconsistency
{
  /**
   * Row of the finding in our own table.
   */
  uint64_t serial_id;

  /**
   * Row of the wire transfer in the bank's credit history.  This is what
   * the two sides are matched on: the exchange stores it in
   * `kycauths_in.wire_reference`.
   */
  uint64_t bank_row_id;

  /**
   * Amount the exchange claims to have received, zero if the exchange
   * does not know the transfer at all.
   */
  struct TALER_Amount amount_exchange_expected;

  /**
   * Amount the bank says it transferred, zero if the bank does not
   * report the transfer at all.
   */
  struct TALER_Amount amount_wired;

  /**
   * Account public key the transfer established, as known to whichever
   * side did report the transfer.
   */
  union TALER_AccountPublicKeyP account_pub;

  /**
   * When the transfer was executed.
   */
  struct GNUNET_TIME_Absolute timestamp;

  /**
   * Bank account that was debited, as known to whichever side did report
   * the transfer.
   */
  struct TALER_FullPayto account;

  /**
   * Human-readable description of what does not match.
   */
  char *diagnostic;

  bool suppressed;

};

/**
 * Balance values for a reserve (or all reserves).
 */
struct TALER_AUDITORDB_ReserveFeeBalance
{
  /**
   * Remaining funds.
   */
  struct TALER_Amount reserve_balance;

  /**
   * Losses from operations that should not have
   * happened (e.g. negative balance).
   */
  struct TALER_Amount reserve_loss;

  /**
   * Fees charged for withdraw.
   */
  struct TALER_Amount withdraw_fee_balance;

  /**
   * Fees charged for closing.
   */
  struct TALER_Amount close_fee_balance;

  /**
   * Fees charged for purse creation.
   */
  struct TALER_Amount purse_fee_balance;

  /**
   * Opening fees charged.
   */
  struct TALER_Amount open_fee_balance;

  /**
   * History fees charged.
   */
  struct TALER_Amount history_fee_balance;
};


/**
 * Balance data for denominations in circulation.
 */
struct TALER_AUDITORDB_DenominationCirculationData
{
  /**
   * Amount of outstanding coins in circulation.
   */
  struct TALER_Amount denom_balance;

  /**
   * Amount lost due coins illicitly accepted (effectively, a
   * negative @a denom_balance).
   */
  struct TALER_Amount denom_loss;

  /**
   * Total amount that could still be theoretically lost in the future due to
   * recoup operations.  (Total put into circulation minus @e recoup_loss).
   */
  struct TALER_Amount denom_risk;

  /**
   * Amount lost due to recoups.
   */
  struct TALER_Amount recoup_loss;

  /**
   * Number of coins of this denomination that the exchange signed into
   * existence.
   */
  uint64_t num_issued;
};

struct TALER_AUDITORDB_DenominationsWithoutSigs
{
  uint64_t row_id;
  struct TALER_DenominationHashP denompub_h;
  struct TALER_Amount value;
  struct GNUNET_TIME_Absolute start_time;
  struct GNUNET_TIME_Absolute end_time;
  bool suppressed;
};

struct TALER_AUDITORDB_MisattributionInInconsistency
{
  uint64_t row_id;
  struct TALER_Amount amount;
  uint64_t bank_row;
  struct TALER_ReservePublicKeyP reserve_pub;
  bool suppressed;

};

struct TALER_AUDITORDB_DenominationPending
{
  uint64_t row_id;
  struct TALER_DenominationHashP denom_pub_hash;
  struct TALER_Amount denom_balance;
  struct TALER_Amount denom_loss;
  uint64_t num_issued;
  struct TALER_Amount denom_risk;
  struct TALER_Amount recoup_loss;
  bool suppressed;

};

struct TALER_AUDITORDB_HistoricReserveSummary
{
  uint64_t row_id;
  struct GNUNET_TIME_Absolute start_date;
  struct GNUNET_TIME_Absolute end_date;
  struct TALER_Amount reserve_profits;
  bool suppressed;

};

struct TALER_AUDITORDB_WireFormatInconsistency
{
  uint64_t row_id;
  struct TALER_Amount amount;
  uint64_t wire_offset;
  char *diagnostic;
  bool suppressed;

};

struct TALER_AUDITORDB_WireOutInconsistency
{
  uint64_t row_id;
  struct TALER_FullPayto destination_account;
  char *diagnostic;
  uint64_t wire_out_row_id;
  struct TALER_Amount expected;
  struct TALER_Amount claimed;
  bool suppressed;

};

struct TALER_AUDITORDB_RowMinorInconsistencies
{
  uint64_t row_id;
  char *row_table;
  uint64_t problem_row;
  char *diagnostic;
  bool suppressed;
};


struct TALER_AUDITORDB_ReserveBalanceSummaryWrongInconsistency
{
  uint64_t row_id;
  struct TALER_ReservePublicKeyP reserve_pub;
  struct TALER_Amount exchange_amount;
  struct TALER_Amount auditor_amount;
  bool suppressed;

};

struct TALER_AUDITORDB_ReserveNotClosedInconsistency
{
  uint64_t row_id;
  struct TALER_ReservePublicKeyP reserve_pub;
  struct TALER_Amount balance;
  struct GNUNET_TIME_Absolute expiration_time;
  char *diagnostic;
  bool suppressed;

};


enum TALER_AUDITORDB_DeletableSuppressableTables
{
  /**
   * For auditor_amount_arithmetic_inconsistency table.
   */
  TALER_AUDITORDB_AMOUNT_ARITHMETIC_INCONSISTENCY,

  /**
   * For auditor_closure_lags table.
   */
  TALER_AUDITORDB_CLOSURE_LAGS,

  /**
   * For auditor_bad_sig_losses table.
   */
  TALER_AUDITORDB_BAD_SIG_LOSSES,

  /**
   * For auditor_coin_inconsistency table.
   */
  TALER_AUDITORDB_COIN_INCONSISTENCY,

  /**
   * For auditor_denomination_key_validity_withdraw_inconsistency table.
   */
  TALER_AUDITORDB_DENOMINATION_KEY_VALIDITY_WITHDRAW_INCONSISTENCY,

  /**
   * For auditor_denomination_pending table.
   */
  TALER_AUDITORDB_DENOMINATION_PENDING,

  /**
   * For auditor_denominations_without_sig table.
   */
  TALER_AUDITORDB_DENOMINATIONS_WITHOUT_SIG,

  /**
   * For auditor_deposit_confirmation table.
   */
  TALER_AUDITORDB_DEPOSIT_CONFIRMATION,

  /**
   * For auditor_emergency table.
   */
  TALER_AUDITORDB_EMERGENCY,

  /**
   * For auditor_emergency_by_count table.
   */
  TALER_AUDITORDB_EMERGENCY_BY_COUNT,

  /**
   * For auditor_fee_time_inconsistency table.
   */
  TALER_AUDITORDB_FEE_TIME_INCONSISTENCY,

  /**
   * For auditor_misattribution_in_inconsistency table.
   */
  TALER_AUDITORDB_MISATTRIBUTION_IN_INCONSISTENCY,

  /**
   * For auditor_purse_not_closed_inconsistency table.
   */
  TALER_AUDITORDB_PURSE_NOT_CLOSED_INCONSISTENCY,

  /**
   * For auditor_refreshes_hanging table.
   */
  TALER_AUDITORDB_REFRESHES_HANGING,

  /**
   * For auditor_reserve_balance_insufficient_inconsistency table.
   */
  TALER_AUDITORDB_RESERVE_BALANCE_INSUFFICIENT_INCONSISTENCY,

  /**
   * For auditor_reserve_balance_summary_wrong_inconsistency table.
   */
  TALER_AUDITORDB_RESERVE_BALANCE_SUMMARY_WRONG_INCONSISTENCY,

  /**
   * For auditor_reserve_in_inconsistency table.
   */
  TALER_AUDITORDB_RESERVE_IN_INCONSISTENCY,

  /**
   * For auditor_reserve_not_closed_inconsistency table.
   */
  TALER_AUDITORDB_RESERVE_NOT_CLOSED_INCONSISTENCY,

  /**
   * For auditor_row_inconsistency table.
   */
  TALER_AUDITORDB_ROW_INCONSISTENCY,

  /**
   * For auditor_row_minor_inconsistency table.
   */
  TALER_AUDITORDB_ROW_MINOR_INCONSISTENCY,

  /**
   * For auditor_wire_format_inconsistency table.
   */
  TALER_AUDITORDB_WIRE_FORMAT_INCONSISTENCY,

  /**
   * For auditor_wire_out_inconsistency table.
   */
  TALER_AUDITORDB_WIRE_OUT_INCONSISTENCY,

  /**
   * For auditor_kycauth_in_inconsistency table.  Note that new values
   * must be appended here rather than inserted alphabetically: the
   * numbering is what `TALER_AUDITORDB_get_deletable_suppressable_table_name()`
   * indexes its table with.
   */
  TALER_AUDITORDB_KYCAUTH_IN_INCONSISTENCY,

  /**
   * For auditor_aml_holds table.
   */
  TALER_AUDITORDB_AML_HOLDS,

  /**
   * Terminal.
   */
  TALER_AUDITORDB_DELETABLESUPPRESSABLE_TABLES_MAX
};


/**
 * Information about a wire transfer the exchange aggregated but did not
 * execute.
 */
struct TALER_AUDITORDB_AmlHold
{
  uint64_t row_id;

  /**
   * Wire transfer the deposits were aggregated into.
   */
  struct TALER_WireTransferIdentifierRawP wtid;

  /**
   * Account the transfer should be made to.
   */
  struct TALER_FullPaytoHashP wire_target_h_payto;

  /**
   * Payto URI of @e wire_target_h_payto.
   */
  struct TALER_FullPayto account;

  /**
   * What the exchange still owes on this transfer.
   */
  struct TALER_Amount amount;

  /**
   * Why the exchange says it has not made the transfer, an
   * `enum TALER_EXCHANGEDB_DeferralReason` value taken from its
   * `aggregation_deferrals` row.  Zero if the exchange gave no reason at all,
   * which is the case that says it is simply not paying.
   */
  uint32_t deferral_reason;

  /**
   * Measure the exchange named as blocking the payout, or 0 if it named none.
   */
  uint64_t legitimization_measure_serial_id;

  /**
   * When did the auditor first see this transfer being held?
   */
  struct GNUNET_TIME_Absolute creation_date;

  bool suppressed;
};


/**
 * Information about an arithmetic inconsistency
 */
struct TALER_AUDITORDB_AmountArithmeticInconsistency
{
  uint64_t row_id;
  uint64_t problem_row_id;
  char *operation;
  struct TALER_Amount exchange_amount;
  struct TALER_Amount auditor_amount;
  bool profitable;
  bool suppressed;
};


/**
 * Initialize database connection.
 *
 * @param cfg configuration to use
 * @return NULL on failure
 */
struct TALER_AUDITORDB_PostgresContext *
TALER_AUDITORDB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);


/**
 * Shutdown the database connection.
 *
 * @param[in] pg connection to disconnect
 */
void
TALER_AUDITORDB_disconnect (struct TALER_AUDITORDB_PostgresContext *pg);


#endif
