/*
   This file is part of TALER
   Copyright (C) 2025, 2026 Taler Systems SA

   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero 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 Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License along with
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
/**
 * @file include/taler/exchange/get-aml-OFFICER_PUB-decisions.h
 * @brief C interface for the GET /aml/$OFFICER_PUB/decisions endpoint
 * @author Christian Grothoff
 */
#ifndef _TALER_EXCHANGE__GET_AML_OFFICER_PUB_DECISIONS_H
#define _TALER_EXCHANGE__GET_AML_OFFICER_PUB_DECISIONS_H

#include <taler/exchange/common.h>

/**
 * Possible options we can set for the GET decisions request.
 */
enum TALER_EXCHANGE_GetAmlDecisionsOption
{
  /**
   * End of list of options.
   */
  TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_END = 0,

  /**
   * Return at most N values, default is -20 to return
   * the last 20 entries before start. Negative values
   * to return before limit, positive to return after limit.
   */
  TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_LIMIT,

  /**
   * Row number threshold, defaults to INT64_MAX, namely
   * the biggest row id possible in the database.
   */
  TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_OFFSET,

  /**
   * Filter by account using a normalized payto URI hash.
   */
  TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_H_PAYTO,

  /**
   * If set to #TALER_EXCHANGE_YNA_YES, only return active
   * results, #TALER_EXCHANGE_YNA_NO, only return inactive
   * results, #TALER_EXCHANGE_YNA_ALL, to return all
   * decisions. Default is all.
   */
  TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_ACTIVE,

  /**
   * If set to #TALER_EXCHANGE_YNA_YES, only return accounts
   * under investigation, #TALER_EXCHANGE_YNA_NO, only return
   * accounts not under investigation, #TALER_EXCHANGE_YNA_ALL,
   * to return all accounts. Default is all.
   */
  TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_INVESTIGATION

};


/**
 * Possible options we can set for the GET decisions request.
 */
struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
{

  /**
   * Type of the option being set.
   */
  enum TALER_EXCHANGE_GetAmlDecisionsOption option;

  /**
   * Specific option value.
   */
  union
  {

    /**
     * Value of if @e option is TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_LIMIT.
     */
    int64_t limit;

    /**
     * Value of if @e option is TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_OFFSET.
     * Note that in practice the maximum value is INT64_MAX, even though
     * this value is unsigned.
     */
    uint64_t offset;

    /**
     * Value of if @e option is TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_H_PAYTO.
     */
    const struct TALER_NormalizedPaytoHashP *h_payto;

    /**
     * Value of if @e option is TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_ACTIVE.
     */
    enum TALER_EXCHANGE_YesNoAll active;

    /**
     * Value of if @e option is TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_INVESTIGATION.
     */
    enum TALER_EXCHANGE_YesNoAll investigation;

  } details;

};


/**
 * Handle for an operation to GET /aml/$OFFICER_PUB/decisions.
 */
struct TALER_EXCHANGE_GetAmlDecisionsHandle;


/**
 * Information about a KYC rule.
 */
struct TALER_EXCHANGE_GetAmlDecisionsKycRule
{
  /**
   * Type of operation to which the rule applies.
   */
  enum TALER_KYCLOGIC_KycTriggerEvent operation_type;

  /**
   * Name of the configuration section this rule originates from.
   * Can be NULL.
   */
  const char *rule_name;

  /**
   * The threshold amount that triggers the measures.
   */
  struct TALER_Amount threshold;

  /**
   * Over which duration should the threshold be computed.
   */
  struct GNUNET_TIME_Relative timeframe;

  /**
   * Length of the @e measures array.
   */
  size_t measures_length;

  /**
   * Array of names of measures to apply.
   */
  const char **measures;

  /**
   * Display priority for this rule.
   */
  int64_t display_priority;

  /**
   * True if the rule should be exposed to the client.
   */
  bool exposed;

  /**
   * True if all measures need to be satisfied (AND combinator),
   * false if any measure is sufficient (OR combinator).
   */
  bool is_and_combinator;
};


/**
 * Legitimization rule set associated with an AML decision.
 */
struct TALER_EXCHANGE_GetAmlDecisionsLegitimizationRuleSet
{
  /**
   * When does this set of rules expire?
   */
  struct GNUNET_TIME_Timestamp expiration_time;

  /**
   * Name of the successor measure to apply when expiration time is reached.
   * Can be NULL.
   */
  const char *successor_measure;

  /**
   * Length of the @e rules array.
   */
  size_t rules_length;

  /**
   * Array of KYC rules. NOT allocated here!
   */
  const struct TALER_EXCHANGE_GetAmlDecisionsKycRule *rules;

  /**
   * Custom measures.
   */
  const json_t *custom_measures;
};


/**
 * Entry in the set of AML decisions that are returned
 * by the server in a single request.
 */
struct TALER_EXCHANGE_GetAmlDecisionsDecision
{
  /**
   * Hash of the normalized payto:// URI of the account the
   * decision applies to.
   */
  struct TALER_NormalizedPaytoHashP h_payto;

  /**
   * Full payto:// URI of the account the decision applies to.
   * Since protocol v30 (rev 1).
   */
  const char *full_payto;

  /**
   * True if the underlying payto://-URI is for a wallet.
   */
  bool is_wallet;

  /**
   * Row ID of the decision in the exchange database.
   */
  uint64_t rowid;

  /**
   * Justification for the decision. Can be NULL.
   */
  const char *justification;

  /**
   * When was the decision made?
   */
  struct GNUNET_TIME_Timestamp decision_time;

  /**
   * Account properties. Can be NULL if no properties are set.
   */
  const json_t *properties;

  /**
   * Legitimization rules that apply to this account.
   */
  struct TALER_EXCHANGE_GetAmlDecisionsLegitimizationRuleSet limits;

  /**
   * True if the account is under investigation by AML staff.
   */
  bool to_investigate;

  /**
   * True if this is the active decision for the account.
   */
  bool is_active;
};


/**
 * Information returned from the exchange for a
 * GET /aml/$OFFICER_PUB/decisions request.
 */
struct TALER_EXCHANGE_GetAmlDecisionsResponse
{
  /**
   * HTTP response data
   */
  struct TALER_EXCHANGE_HttpResponse hr;

  /**
   * Details depending on the HTTP status code.
   */
  union
  {

    /**
     * Details on #MHD_HTTP_OK.
     */
    struct
    {
      /**
       * Length of the @e records array.
       */
      size_t records_length;

      /**
       * AML decisions.
       */
      const struct TALER_EXCHANGE_GetAmlDecisionsDecision *records;

    } ok;

  } details;
};


/**
 * Set up GET /aml/$OPUB/decisions operation.
 * Note that you must explicitly start the operation after
 * possibly setting options.
 *
 * @param ctx the context
 * @param url base URL of the exchange
 * @param officer_priv private key of the officer
 * @return handle to operation
 */
struct TALER_EXCHANGE_GetAmlDecisionsHandle *
TALER_EXCHANGE_get_aml_decisions_create (
  struct GNUNET_CURL_Context *ctx,
  const char *url,
  const struct TALER_AmlOfficerPrivateKeyP *officer_priv);


/**
 * Terminate the list of the options.
 *
 * @return the terminating object of struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
 */
#define TALER_EXCHANGE_get_aml_decisions_option_end_()            \
        (const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue)  \
        {                                                         \
          .option = TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_END   \
        }

/**
 * Set limit @a l on the number of results to return.
 *
 * @param l limit on the number of results to return
 * @return representation of the option as a struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
 */
#define TALER_EXCHANGE_get_aml_decisions_option_limit(l)           \
        (const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue)   \
        {                                                          \
          .option = TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_LIMIT, \
          .details.limit = (l)                                     \
        }


/**
 * Set row offset from which to return results.
 *
 * @param o offset to use
 * @return representation of the option as a struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
 */
#define TALER_EXCHANGE_get_aml_decisions_option_offset(o)              \
        (const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue)    \
        {                                                           \
          .option = TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_OFFSET, \
          .details.offset = (o)                                     \
        }


/**
 * Set filter on which account to filter AML decisions by.
 *
 * @param p normalized payto URI hash of the account to filter by
 * @return representation of the option as a struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
 */
#define TALER_EXCHANGE_get_aml_decisions_option_filter_h_payto(p)          \
        (const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue)     \
        {                                                            \
          .option = TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_H_PAYTO, \
          .details.h_payto = (p)                                     \
        }

/**
 * Set filter on active (or inactive) results.
 *
 * @param a activity filter to use
 * @return representation of the option as a struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
 */
#define TALER_EXCHANGE_get_aml_decisions_option_filter_active(a)          \
        (const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue)    \
        {                                                           \
          .option = TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_ACTIVE, \
          .details.active = (a)                                     \
        }

/**
 * Set filter on investigation status.
 *
 * @param i investigation filter to use
 * @return representation of the option as a struct TALER_EXCHANGE_GetAmlDecisionsOptionValue
 */
#define TALER_EXCHANGE_get_aml_decisions_option_filter_investigation(i) \
        (const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue)         \
        {                                                                \
          .option = TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_INVESTIGATION, \
          .details.investigation = (i)                                   \
        }


/**
 * Set the requested options for the operation.
 *
 * If any option fail other options may be or may be not applied.
 *
 * @param adgh the request to set the options for
 * @param num_options length of the @a options array
 * @param options an array of options
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_get_aml_decisions_set_options_ (
  struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
  unsigned int num_options,
  const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue options[]);


/**
 * Set the requested options for the operation.
 *
 * If any option fail other options may be or may be not applied.
 *
 * It should be used with helpers that creates required options, for example:
 *
 * TALER_EXCHANGE_get_aml_decisions_set_options (
 *   adgh,
 *   TALER_EXCHANGE_get_aml_decisions_option_h_payto_(&h_payto));
 *
 * @param adgh the request to set the options for
 * @param ... the list of the options, each option must be created
 *            by helpers TALER_EXCHANGE_get_aml_decisions_option_NAME(VALUE)
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO on failure,
 *         #GNUNET_SYSERR on internal error
 */
#define TALER_EXCHANGE_get_aml_decisions_set_options(adgh,...)             \
        TALER_EXCHANGE_get_aml_decisions_set_options_ (                     \
          adgh,                                                             \
          TALER_EXCHANGE_COMMON_OPTIONS_ARRAY_MAX_SIZE,                     \
          ((const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue[])       \
           {__VA_ARGS__, TALER_EXCHANGE_get_aml_decisions_option_end_ () }  \
          ))


#ifndef TALER_EXCHANGE_GET_AML_DECISIONS_RESULT_CLOSURE
/**
 * Type of the closure used by
 * the #TALER_EXCHANGE_GetAmlDecisionsCallback.
 */
#define TALER_EXCHANGE_GET_AML_DECISIONS_RESULT_CLOSURE void
#endif /* _TALER_EXCHANGE_GET_AML_OFFICER_PUB_DECISIONS_H */

/**
 * Type of the function that receives the result of a
 * GET /aml/$OFFICER_PUB/decisions request.
 *
 * @param cls closure
 * @param result result returned by the HTTP server
 */
typedef void
(*TALER_EXCHANGE_GetAmlDecisionsCallback)(
  TALER_EXCHANGE_GET_AML_DECISIONS_RESULT_CLOSURE *cls,
  const struct TALER_EXCHANGE_GetAmlDecisionsResponse *result);


/**
 * Start GET /aml/$OPUB/decisions operation.
 *
 * @param[in,out] adgh operation to start
 * @param cb function to call with the exchange's result
 * @param cb_cls closure for @a cb
 * @return status code, #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TALER_EXCHANGE_get_aml_decisions_start (
  struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
  TALER_EXCHANGE_GetAmlDecisionsCallback cb,
  TALER_EXCHANGE_GET_AML_DECISIONS_RESULT_CLOSURE *cb_cls);


/**
 * Cancel GET /aml/$OPUB/decisions operation.  This function
 * must not be called by clients after the
 * TALER_EXCHANGE_GetAmlDecisionsCallback has been invoked
 * (as in those cases it'll be called internally by the
 * implementation already).
 *
 * @param[in] adgh operation to cancel
 */
void
TALER_EXCHANGE_get_aml_decisions_cancel (
  struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh);


#endif /* _TALER_EXCHANGE__GET_AML_OFFICER_PUB_DECISIONS_H */
