/*
  This file is part of Anastasis
  Copyright (C) 2020-2023 Anastasis SARL

  Anastasis 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.

  Anastasis 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
  Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file testing/test_anastasis.c
 * @brief testcase to test anastasis
 * @author Christian Grothoff
 * @author Dennis Neufeld
 * @author Dominik Meister
 */
#include "platform.h"
#include "anastasis_testing_lib.h"
#include <taler/taler_merchant_testing_lib.h>


/**
 * Configuration file we use.  One (big) configuration is used
 * for the various components for this test.
 */
#define CONFIG_FILE "test_anastasis_api.conf"

/**
 * Exchange base URL.  Could also be taken from config.
 */
#define EXCHANGE_URL "http://localhost:8081/"

/**
 * IBAN of the account the merchant is paid into.  Unlike the accounts of
 * the payer and of the exchange, this one need not exist at the bank: the
 * test never runs the aggregator, so nothing is ever transferred to it.
 */
#define MERCHANT_ACCOUNT_IBAN "DE89370400440532013000"

/**
 * Credentials for the test.  The bank accounts of the payer
 * (@e user42_payto) and of the exchange (@e exchange_payto) are the ones
 * `taler-unified-setup.sh' registers at libeufin-bank.
 */
static struct TALER_TESTING_Credentials cred;

/**
 * Payto URI of the merchant (receiver).
 */
static struct TALER_FullPayto merchant_payto;

/**
 * Merchant base URL.
 */
static const char *merchant_url;

/**
 * Anastasis base URL.
 */
static char *anastasis_url;

/**
 * Name of the file for exchanging the secret.
 */
static char *file_secret;

/**
 * Anastasis process.
 */
static struct GNUNET_Process *anastasisd;

/**
 * Identity to use for testing.
 */
static json_t *id_data;


/**
 * Execute the taler-exchange-wirewatch command with
 * our configuration file.
 *
 * @param label label to use for the command.
 */
static struct TALER_TESTING_Command
cmd_exec_wirewatch (const char *label)
{
  return TALER_TESTING_cmd_exec_wirewatch (label,
                                           CONFIG_FILE);
}


/**
 * Run wire transfer of funds from some user's account to the
 * exchange.
 *
 * @param label label to use for the command.
 * @param amount amount to transfer, i.e. "EUR:1"
 * @param url exchange_url
 */
static struct TALER_TESTING_Command
cmd_transfer_to_exchange (const char *label,
                          const char *amount)
{
  return TALER_TESTING_cmd_admin_add_incoming (label,
                                               amount,
                                               &cred.ba_admin,
                                               cred.user42_payto);
}


/**
 * Main function that will tell the interpreter what commands to
 * run.
 *
 * @param cls closure
 */
static void
run (void *cls,
     struct TALER_TESTING_Interpreter *is)
{
  struct TALER_TESTING_Command pay[] = {
    /**
     * Move money to the exchange's bank account.
     */
    cmd_transfer_to_exchange ("create-reserve-1",
                              "EUR:10.02"),
    /**
     * Make a reserve exist, according to the previous
     * transfer.
     */
    cmd_exec_wirewatch ("wirewatch-1"),
    TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
                                       "create-reserve-1",
                                       "EUR:5",
                                       0, /* age */
                                       MHD_HTTP_OK),
    TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
                                       "create-reserve-1",
                                       "EUR:5",
                                       0, /* age */
                                       MHD_HTTP_OK),
    /**
     * Check the reserve is depleted.
     */
    TALER_TESTING_cmd_status ("withdraw-status-1",
                              "create-reserve-1",
                              "EUR:0",
                              MHD_HTTP_OK),
    TALER_TESTING_cmd_end ()
  };

  struct TALER_TESTING_Command anastasis[] = {
    ANASTASIS_TESTING_cmd_config ("salt-request-1",
                                  anastasis_url,
                                  MHD_HTTP_OK),
    ANASTASIS_TESTING_cmd_truth_upload_question ("truth-create-1",
                                                 anastasis_url,
                                                 id_data,
                                                 "answer the question",
                                                 "text/plain",
                                                 "SomeTruth1",
                                                 MHD_HTTP_NO_CONTENT,
                                                 ANASTASIS_TESTING_TSO_NONE,
                                                 "salt-request-1"),
    ANASTASIS_TESTING_cmd_truth_upload_question ("truth-create-2",
                                                 anastasis_url,
                                                 id_data,
                                                 "answer the question",
                                                 "text/plain",
                                                 "SomeTruth2",
                                                 MHD_HTTP_NO_CONTENT,
                                                 ANASTASIS_TESTING_TSO_NONE,
                                                 "salt-request-1"),
    ANASTASIS_TESTING_cmd_truth_upload ("truth-create-3",
                                        anastasis_url,
                                        id_data,
                                        "file",
                                        "read the file",
                                        "text/plain",
                                        file_secret,
                                        strlen (file_secret),
                                        MHD_HTTP_NO_CONTENT,
                                        ANASTASIS_TESTING_TSO_NONE,
                                        "salt-request-1"),
    ANASTASIS_TESTING_cmd_policy_create ("policy-create-1",
                                         "truth-create-1",
                                         "truth-create-2",
                                         NULL),
    ANASTASIS_TESTING_cmd_policy_create ("policy-create-2",
                                         "truth-create-1",
                                         "truth-create-3",
                                         NULL),
    ANASTASIS_TESTING_cmd_policy_create ("policy-create-3",
                                         "truth-create-2",
                                         "truth-create-3",
                                         NULL),
    ANASTASIS_TESTING_cmd_secret_share ("secret-share-1",
                                        anastasis_url,
                                        "salt-request-1",
                                        NULL,
                                        id_data,
                                        "core secret",
                                        strlen ("core secret"),
                                        ANASTASIS_SHARE_STATUS_PAYMENT_REQUIRED,
                                        ANASTASIS_TESTING_SSO_NONE,
                                        "policy-create-1",
                                        "policy-create-2",
                                        "policy-create-3",
                                        NULL),
    /* what would we have to pay? */
    TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal",
                                            merchant_url,
                                            MHD_HTTP_OK,
                                            "secret-share-1",
                                            NULL),
    /* make the payment */
    TALER_TESTING_cmd_merchant_pay_order_choices (
      "pay-account",
      merchant_url,
      MHD_HTTP_OK,
      "fetch-proposal",
      "withdraw-coin-1",
      "EUR:5",
      "EUR:4.99", /* must match ANNUAL_FEE in config! */
      NULL,
      /* Anastasis creates "v1" orders now; every configured currency
         is a choice and the first one is the primary currency. */
      0,
      NULL),
    ANASTASIS_TESTING_cmd_secret_share ("secret-share-2",
                                        anastasis_url,
                                        "salt-request-1",
                                        "secret-share-1",
                                        id_data,
                                        "core secret",
                                        strlen ("core secret"),
                                        ANASTASIS_SHARE_STATUS_SUCCESS,
                                        ANASTASIS_TESTING_SSO_NONE,
                                        "policy-create-1",
                                        "policy-create-2",
                                        "policy-create-3",
                                        NULL),
    ANASTASIS_TESTING_cmd_recover_secret ("recover-secret-1",
                                          anastasis_url,
                                          id_data,
                                          0, /* version */
                                          ANASTASIS_TESTING_RSO_NONE,
                                          "salt-request-1",
                                          "secret-share-2"),
    ANASTASIS_TESTING_cmd_challenge_answer ("challenge-answer-1",
                                            NULL, /* payment ref */
                                            "recover-secret-1", /* challenge ref */
                                            0, /* challenge index */
                                            "SomeTruth1",
                                            0,  /* mode */
                                            ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED),
#if 0
    ANASTASIS_TESTING_cmd_challenge_answer ("challenge-answer-2",
                                            NULL, /* payment ref */
                                            "recover-secret-1",
                                            1, /* challenge index */
                                            "SomeTruth2",
                                            0, /* mode */
                                            ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED),
#endif
    ANASTASIS_TESTING_cmd_challenge_start ("challenge-start-3-pay",
                                           NULL,  /* payment ref */
                                           "recover-secret-1",
                                           2,  /* challenge index */
                                           ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED),
    TALER_TESTING_cmd_merchant_claim_order ("fetch-challenge-pay-proposal",
                                            merchant_url,
                                            MHD_HTTP_OK,
                                            "challenge-start-3-pay",
                                            NULL),
    TALER_TESTING_cmd_merchant_pay_order_choices (
      "pay-file-challenge",
      merchant_url,
      MHD_HTTP_OK,
      "fetch-challenge-pay-proposal",
      "withdraw-coin-2",
      "EUR:1",
      "EUR:1", /* must match COST in config! */
      NULL,
      /* Anastasis creates "v1" orders now; every configured currency
         is a choice and the first one is the primary currency. */
      0,
      NULL),
    ANASTASIS_TESTING_cmd_challenge_start ("challenge-start-3-paid",
                                           "challenge-start-3-pay",  /* payment ref */
                                           "recover-secret-1",
                                           2,  /* challenge index */
                                           ANASTASIS_CHALLENGE_START_STATUS_FILENAME_PROVIDED),
    ANASTASIS_TESTING_cmd_challenge_answer ("challenge-answer-3",
                                            "challenge-start-3-pay", /* payment ref */
                                            "recover-secret-1",
                                            2, /* challenge index */
                                            "challenge-start-3-paid", /* answer */
                                            1, /* mode */
                                            ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED),
    ANASTASIS_TESTING_cmd_recover_secret_finish ("recover-finish-1",
                                                 "recover-secret-1",
                                                 GNUNET_TIME_UNIT_SECONDS),
    TALER_TESTING_cmd_end ()
  };

  struct TALER_TESTING_Command commands[] = {
    /* general setup */
    TALER_TESTING_cmd_system_start ("start-taler",
                                    CONFIG_FILE,
                                    "-bem",
                                    "-d", "iban",
                                    "-u", "exchange-account-exchange",
                                    NULL),
    TALER_TESTING_cmd_get_exchange ("get-exchange",
                                    cred.cfg,
                                    NULL,
                                    true,
                                    true),
    /* Not TALER_TESTING_cmd_merchant_post_instances(): that one gives the
       instance a pay delay of two seconds, and the orders here are created
       by anastasis-httpd, not by the test, so a slow order creation would
       expire the offer before the test gets to pay it. */
    TALER_TESTING_cmd_merchant_post_instances2 ("instance-create-admin",
                                                merchant_url,
                                                "admin",
                                                "admin",
                                                json_pack ("{s:s}",
                                                           "city",
                                                           "shopcity"),
                                                json_pack ("{s:s}",
                                                           "city",
                                                           "lawyercity"),
                                                true, /* use STEFAN */
                                                GNUNET_TIME_UNIT_ZERO,
                                                GNUNET_TIME_UNIT_MINUTES,
                                                NULL, /* auth token */
                                                MHD_HTTP_NO_CONTENT),
    TALER_TESTING_cmd_merchant_post_account (
      "instance-create-default-account",
      merchant_url,
      merchant_payto,
      NULL, NULL,
      MHD_HTTP_OK),
    TALER_TESTING_cmd_batch ("pay",
                             pay),
    TALER_TESTING_cmd_batch ("anastasis",
                             anastasis),
    TALER_TESTING_cmd_end ()
  };

  TALER_TESTING_run (is,
                     commands);
}


int
main (int argc,
      char *const *argv)
{
  int ret;
  file_secret = ANASTASIS_TESTING_make_file_challenge_name (CONFIG_FILE);
  if (NULL == file_secret)
    return 77;
  id_data = ANASTASIS_TESTING_make_id_data_example ("MaxMuster123456789");
  merchant_payto.full_payto =
    (char *) "payto://iban/SANDBOXX/" MERCHANT_ACCOUNT_IBAN
    "?receiver-name=merchant";
  merchant_url = "http://localhost:8080/";

  if (NULL ==
      (anastasis_url = ANASTASIS_TESTING_prepare_anastasis (CONFIG_FILE)))
    return 77;
  if (NULL == (anastasisd =
                 ANASTASIS_TESTING_run_anastasis (CONFIG_FILE,
                                                  anastasis_url)))
  {
    GNUNET_break (0);
    return 1;
  }
  ret = TALER_TESTING_main (argv,
                            "INFO",
                            CONFIG_FILE,
                            "exchange-account-exchange",
                            TALER_TESTING_BS_IBAN,
                            &cred,
                            &run,
                            NULL);
  GNUNET_break (GNUNET_OK ==
                GNUNET_process_kill (anastasisd,
                                     SIGTERM));
  GNUNET_break (GNUNET_OK ==
                GNUNET_process_wait (anastasisd,
                                     true,
                                     NULL,
                                     NULL));
  GNUNET_process_destroy (anastasisd);
  GNUNET_free (anastasis_url);
  return ret;
}


/* end of test_anastasis.c */
