/*
  This file is part of TALER
  Copyright (C) 2023, 2024 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 do_persist_aml_program_result.c
 * @brief helper function store results of AML programs
 * @author Christian Grothoff
 */
#include "exchangedb_lib.h"
#include "taler/taler_kyclogic_lib.h"
#include "exchange-database/insert_aml_decision.h"
#include "exchange-database/insert_aml_program_failure.h"
#include "exchange-database/insert_successor_measure.h"
#include "exchange-database/do_persist_aml_program_result.h"
#include "helper.h"
#include <gnunet/gnunet_common.h>


enum GNUNET_DB_QueryStatus
TALER_EXCHANGEDB_do_persist_aml_program_result (
  struct TALER_EXCHANGEDB_PostgresContext *pg,
  uint64_t process_row,
  const struct TALER_NormalizedPaytoHashP *account_id,
  const struct TALER_KYCLOGIC_AmlProgramResult *apr,
  enum TALER_EXCHANGEDB_PersistProgramResultStatus *ret_pprs)
{
  enum GNUNET_DB_QueryStatus qs;
  json_t *jmeasures = NULL;
  struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;

  GNUNET_assert (NULL != ret_pprs);

  *ret_pprs = TALER_EXCHANGEDB_PPRS_OK;

  if ( (TALER_KYCLOGIC_AMLR_SUCCESS == apr->status) &&
       (NULL != apr->details.success.new_measures) )
  {
    lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules);
    if (NULL == lrs)
    {
      qs = TALER_EXCHANGEDB_insert_aml_program_failure (
        pg,
        process_row,
        account_id,
        "Failed to parse AML program output",
        TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT);
      GNUNET_break (qs > 0);
      return qs;
    }
    jmeasures = TALER_KYCLOGIC_get_jmeasures (
      lrs,
      apr->details.success.new_measures);
    if (NULL == jmeasures)
    {
      char *err;

      GNUNET_break (0);
      GNUNET_asprintf (&err,
                       "Failed to find measures `%s' specified in AML program output",
                       apr->details.success.new_measures);
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "AML program specified invalid measures `%s'\n",
                  apr->details.success.new_measures);
      qs = TALER_EXCHANGEDB_insert_aml_program_failure (
        pg,
        process_row,
        account_id,
        err,
        TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT);
      *ret_pprs = TALER_EXCHANGEDB_PPRS_BAD_OUTCOME;
      TALER_KYCLOGIC_rules_free (lrs);
      GNUNET_free (err);
      GNUNET_break (qs > 0);
      return qs;
    }
  }

  qs = TALER_EXCHANGEDB_update_to_aml_unlocked (
    pg,
    account_id);
  if (qs < 0)
  {
    GNUNET_break (0);
    goto cleanup;
  }
  switch (apr->status)
  {
  case TALER_KYCLOGIC_AMLR_FAILURE:
    qs = TALER_EXCHANGEDB_insert_aml_program_failure (
      pg,
      process_row,
      account_id,
      apr->details.failure.error_message,
      apr->details.failure.ec);
    GNUNET_break (qs > 0);
    goto cleanup;
  case TALER_KYCLOGIC_AMLR_SUCCESS:
    {
      struct TALER_FullPayto null_payto_uri = { 0 };
      bool invalid_officer;
      bool unknown_account;
      struct GNUNET_TIME_Timestamp last_date;
      uint64_t legitimization_measure_serial_id;
      bool is_wallet;

      qs = TALER_EXCHANGEDB_insert_aml_decision (
        pg,
        null_payto_uri,
        account_id,
        GNUNET_TIME_timestamp_get (),
        apr->details.success.expiration_time,
        apr->details.success.account_properties,
        apr->details.success.new_rules,
        apr->details.success.to_investigate,
        apr->details.success.new_measures,
        jmeasures,
        NULL, /* justification */
        NULL, /* decider_pub */
        NULL, /* decider_sig */
        apr->details.success.num_events,
        apr->details.success.events,
        NULL, /* form ID */
        0, /* enc_attributes_size*/
        NULL, /* enc_attributes*/
        NULL, /* attributes_hash */
        GNUNET_TIME_UNIT_ZERO_TS, /* attributes_expiration_time */
        &invalid_officer,
        &unknown_account,
        &last_date,
        &legitimization_measure_serial_id,
        &is_wallet);
      GNUNET_break (qs > 0);
      goto cleanup;
    }
  }
  GNUNET_break (0);
  qs = GNUNET_DB_STATUS_HARD_ERROR;
cleanup:
  TALER_KYCLOGIC_rules_free (lrs);
  json_decref (jmeasures);
  return qs;
}
