/*
  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/"

/**
 * Account number of the exchange at the bank.
 */
#define EXCHANGE_ACCOUNT_NAME "2"

/**
 * Account number of some user.
 */
#define USER_ACCOUNT_NAME "62"

/**
 * Account number used by the merchant
 */
#define MERCHANT_ACCOUNT_NAME "3"

/**
 * Test credentials.
 */
static struct TALER_TESTING_Credentials cred;

/**
 * Payto URI of the customer (payer).
 */
static const char *payer_payto;

/**
 * Payto URI of the exchange (escrow account).
 */
static const char *exchange_payto;

/**
 * Payto URI of the merchant (receiver).
 */
static const char *merchant_payto;

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

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

/**
 * Anastasis process.
 */
static struct GNUNET_OS_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 (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,
                                               payer_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_run_fakebank ("run-fakebank",
                                    cred.cfg,
                                    "exchange-account-exchange"),
    TALER_TESTING_cmd_system_start ("start-taler",
                                    CONFIG_FILE,
                                    "-em",
                                    "-u", "exchange-account-exchange",
                                    NULL),
    TALER_TESTING_cmd_get_exchange ("get-exchange",
                                    cred.cfg,
                                    NULL,
                                    true,
                                    true),
    TALER_TESTING_cmd_merchant_post_instances ("instance-create-default",
                                               merchant_url,
                                               "default",
                                               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;

  {
    char dir[] = "/tmp/test-anastasis-file-XXXXXX";

    if (NULL == mkdtemp (dir))
    {
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
                                "mkdtemp",
                                dir);
      return 77;
    }
    GNUNET_asprintf (&file_secret,
                     "%s/.secret",
                     dir);
  }
  payer_payto =
    "payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME
    "?receiver-name=62";
  exchange_payto =
    "payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME
    "?receiver-name=exchange";
  merchant_payto =
    "payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME
    "?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_FAKEBANK,
                            &cred,
                            &run,
                            NULL);
  GNUNET_OS_process_kill (anastasisd,
                          SIGTERM);
  GNUNET_OS_process_wait (anastasisd);
  GNUNET_OS_process_destroy (anastasisd);
  GNUNET_free (anastasis_url);
  return ret;
}


/* end of test_anastasis_api.c */
