/*
  This file is part of TALER
  Copyright (C) 2023 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 
*/
/**
 * @file taler-exchange-httpd_aml-decision-get.c
 * @brief Return summary information about AML decision
 * @author Christian Grothoff
 */
#include "platform.h"
#include 
#include 
#include 
#include 
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler_signatures.h"
#include "taler-exchange-httpd.h"
#include "taler_exchangedb_plugin.h"
#include "taler-exchange-httpd_aml-decision.h"
#include "taler-exchange-httpd_metrics.h"
/**
 * Maximum number of records we return per request.
 */
#define MAX_RECORDS 1024
/**
 * Callback with KYC attributes about a particular user.
 *
 * @param[in,out] cls closure with a `json_t *` array to update
 * @param h_payto account for which the attribute data is stored
 * @param provider_section provider that must be checked
 * @param collection_time when was the data collected
 * @param expiration_time when does the data expire
 * @param enc_attributes_size number of bytes in @a enc_attributes
 * @param enc_attributes encrypted attribute data
 */
static void
kyc_attribute_cb (
  void *cls,
  const struct TALER_PaytoHashP *h_payto,
  const char *provider_section,
  struct GNUNET_TIME_Timestamp collection_time,
  struct GNUNET_TIME_Timestamp expiration_time,
  size_t enc_attributes_size,
  const void *enc_attributes)
{
  json_t *kyc_attributes = cls;
  json_t *attributes;
  attributes = TALER_CRYPTO_kyc_attributes_decrypt (&TEH_attribute_key,
                                                    enc_attributes,
                                                    enc_attributes_size);
  GNUNET_break (NULL != attributes);
  GNUNET_assert (
    0 ==
    json_array_append (
      kyc_attributes,
      GNUNET_JSON_PACK (
        GNUNET_JSON_pack_string ("provider_section",
                                 provider_section),
        GNUNET_JSON_pack_timestamp ("collection_time",
                                    collection_time),
        GNUNET_JSON_pack_timestamp ("expiration_time",
                                    expiration_time),
        GNUNET_JSON_pack_allow_null (
          GNUNET_JSON_pack_object_steal ("attributes",
                                         attributes))
        )));
}
/**
 * Return historic AML decision(s).
 *
 * @param[in,out] cls closure with a `json_t *` array to update
 * @param new_threshold new monthly threshold that would trigger an AML check
 * @param new_state AML decision status
 * @param decision_time when was the decision made
 * @param justification human-readable text justifying the decision
 * @param decider_pub public key of the staff member
 * @param decider_sig signature of the staff member
 */
static void
aml_history_cb (
  void *cls,
  const struct TALER_Amount *new_threshold,
  enum TALER_AmlDecisionState new_state,
  struct GNUNET_TIME_Timestamp decision_time,
  const char *justification,
  const struct TALER_AmlOfficerPublicKeyP *decider_pub,
  const struct TALER_AmlOfficerSignatureP *decider_sig)
{
  json_t *aml_history = cls;
  GNUNET_assert (
    0 ==
    json_array_append (
      aml_history,
      GNUNET_JSON_PACK (
        GNUNET_JSON_pack_data_auto ("decider_pub",
                                    decider_pub),
        GNUNET_JSON_pack_string ("justification",
                                 justification),
        TALER_JSON_pack_amount ("new_threshold",
                                new_threshold),
        GNUNET_JSON_pack_int64 ("new_state",
                                new_state),
        GNUNET_JSON_pack_timestamp ("decision_time",
                                    decision_time)
        )));
}
MHD_RESULT
TEH_handler_aml_decision_get (
  struct TEH_RequestContext *rc,
  const struct TALER_AmlOfficerPublicKeyP *officer_pub,
  const char *const args[])
{
  struct TALER_PaytoHashP h_payto;
  if ( (NULL == args[0]) ||
       (GNUNET_OK !=
        GNUNET_STRINGS_string_to_data (args[0],
                                       strlen (args[0]),
                                       &h_payto,
                                       sizeof (h_payto))) )
  {
    GNUNET_break_op (0);
    return TALER_MHD_reply_with_error (rc->connection,
                                       MHD_HTTP_BAD_REQUEST,
                                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
                                       "h_payto");
  }
  if (NULL != args[1])
  {
    GNUNET_break_op (0);
    return TALER_MHD_reply_with_error (rc->connection,
                                       MHD_HTTP_BAD_REQUEST,
                                       TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
                                       args[1]);
  }
  {
    json_t *aml_history;
    json_t *kyc_attributes;
    enum GNUNET_DB_QueryStatus qs;
    bool none = false;
    aml_history = json_array ();
    GNUNET_assert (NULL != aml_history);
    qs = TEH_plugin->select_aml_history (TEH_plugin->cls,
                                         &h_payto,
                                         &aml_history_cb,
                                         aml_history);
    switch (qs)
    {
    case GNUNET_DB_STATUS_HARD_ERROR:
    case GNUNET_DB_STATUS_SOFT_ERROR:
      json_decref (aml_history);
      GNUNET_break (0);
      return TALER_MHD_reply_with_error (rc->connection,
                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
                                         NULL);
    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
      none = true;
      break;
    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
      none = false;
      break;
    }
    kyc_attributes = json_array ();
    GNUNET_assert (NULL != kyc_attributes);
    qs = TEH_plugin->select_kyc_attributes (TEH_plugin->cls,
                                            &h_payto,
                                            &kyc_attribute_cb,
                                            kyc_attributes);
    switch (qs)
    {
    case GNUNET_DB_STATUS_HARD_ERROR:
    case GNUNET_DB_STATUS_SOFT_ERROR:
      json_decref (aml_history);
      json_decref (kyc_attributes);
      GNUNET_break (0);
      return TALER_MHD_reply_with_error (rc->connection,
                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
                                         NULL);
    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
      if (none)
      {
        json_decref (aml_history);
        json_decref (kyc_attributes);
        return TALER_MHD_reply_static (
          rc->connection,
          MHD_HTTP_NO_CONTENT,
          NULL,
          NULL,
          0);
      }
      break;
    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
      break;
    }
    return TALER_MHD_REPLY_JSON_PACK (
      rc->connection,
      MHD_HTTP_OK,
      GNUNET_JSON_pack_array_steal ("aml_history",
                                    aml_history),
      GNUNET_JSON_pack_array_steal ("kyc_attributes",
                                    kyc_attributes));
  }
}
/* end of taler-exchange-httpd_aml-decision_get.c */