/*
  This file is part of Anastasis
  Copyright (C) 2020, 2021 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_api.c
 * @brief testcase to test anastasis' HTTP API interface
 * @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"

/**
 * Test credentials.  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;

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

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

/**
 * 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 withdraw[] = {
    cmd_transfer_to_exchange ("create-reserve-1",
                              "EUR:10.02"),
    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),
    TALER_TESTING_cmd_status ("withdraw-status-1",
                              "create-reserve-1",
                              "EUR:0",
                              MHD_HTTP_OK),
    TALER_TESTING_cmd_end ()
  };

  struct TALER_TESTING_Command policy[] = {
    ANASTASIS_TESTING_cmd_policy_store ("policy-store-1",
                                        anastasis_url,
                                        NULL /* prev upload */,
                                        MHD_HTTP_PAYMENT_REQUIRED,
                                        ANASTASIS_TESTING_PSO_NONE,
                                        "Test-1",
                                        strlen ("Test-1")),
    /* what would we have to pay? */
    TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal",
                                            merchant_url,
                                            MHD_HTTP_OK,
                                            "policy-store-1",
                                            NULL),
    /* make the payment */
    TALER_TESTING_cmd_merchant_pay_order ("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_TESTING_cmd_policy_store ("policy-store-2",
                                        anastasis_url,
                                        "policy-store-1",
                                        MHD_HTTP_NO_CONTENT,
                                        ANASTASIS_TESTING_PSO_NONE,
                                        "Test-1",
                                        strlen ("Test-1")),
    ANASTASIS_TESTING_cmd_policy_lookup ("policy-lookup-1",
                                         anastasis_url,
                                         MHD_HTTP_OK,
                                         "policy-store-2"),
    TALER_TESTING_cmd_end ()
  };

  struct TALER_TESTING_Command truth[] = {
    ANASTASIS_TESTING_cmd_truth_question (
      "truth-store-1",
      anastasis_url,
      NULL,
      "The-Answer",
      ANASTASIS_TESTING_TSO_NONE,
      MHD_HTTP_NO_CONTENT),
    ANASTASIS_TESTING_cmd_truth_solve (
      "keyshare-lookup-1",
      anastasis_url,
      "The-Answer",
      NULL, /* payment ref */
      "truth-store-1",
      0,
      MHD_HTTP_OK),
    ANASTASIS_TESTING_cmd_truth_store (
      "truth-store-2",
      anastasis_url,
      NULL,
      "file",
      "text/plain",
      strlen (file_secret),
      file_secret,
      ANASTASIS_TESTING_TSO_NONE,
      MHD_HTTP_NO_CONTENT),
    ANASTASIS_TESTING_cmd_truth_solve (
      "challenge-fail-1",
      anastasis_url,
      "Wrong-Answer",
      NULL, /* payment ref */
      "truth-store-1", /* upload ref */
      0, /* security question mode */
      MHD_HTTP_FORBIDDEN),
    ANASTASIS_TESTING_cmd_truth_challenge (
      "file-challenge-run-1",
      anastasis_url,
      NULL, /* payment ref */
      "truth-store-2", /* upload ref */
      MHD_HTTP_PAYMENT_REQUIRED),
    /* what would we have to pay? */
    TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal-2",
                                            merchant_url,
                                            MHD_HTTP_OK,
                                            "file-challenge-run-1",
                                            NULL),
    /* make the payment */
    TALER_TESTING_cmd_merchant_pay_order ("pay-account-2",
                                          merchant_url,
                                          MHD_HTTP_OK,
                                          "fetch-proposal-2",
                                          "withdraw-coin-2",
                                          "EUR:1.01",
                                          "EUR:1",
                                          NULL),

    ANASTASIS_TESTING_cmd_truth_challenge (
      "file-challenge-run-2",
      anastasis_url,
      "file-challenge-run-1", /* payment ref */
      "truth-store-2",
      MHD_HTTP_OK),
    ANASTASIS_TESTING_cmd_truth_solve (
      "file-challenge-run-3",
      anastasis_url,
      "file-challenge-run-2", /* answer */
      "file-challenge-run-1", /* payment ref */
      "truth-store-2",
      1,
      MHD_HTTP_OK),
    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),
    ANASTASIS_TESTING_cmd_config ("salt-request-1",
                                  anastasis_url,
                                  MHD_HTTP_OK),
    TALER_TESTING_cmd_batch ("withdraw",
                             withdraw),
    TALER_TESTING_cmd_batch ("policy",
                             policy),
    TALER_TESTING_cmd_batch ("truth",
                             truth),
    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;
  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_api.c */
