/*
  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 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 General Public License for more details.

  You should have received a copy of the GNU General Public
  License along with TALER; see the file COPYING.  If not, see
  <http://www.gnu.org/licenses/>
*/

/**
 * @file testing/testing_api_cmd_checkserver.c
 * @brief Implement a CMD to run an Checkserver service for faking the legitimation service
 * @author Priscilla HUANG
 */
#include "platform.h"
#include "taler/taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler/taler_testing_lib.h"
#include "taler/taler_mhd_lib.h"
#include "taler_merchant_testing_lib.h"
#include "taler_merchant_service.h"
#include <taler/taler_exchange_service.h>


/**
 * State for a "checkserver" CMD.
 */
struct CheckState
{
  /**
   * Handle to the "testserver" service.
   */
  struct MHD_Daemon *mhd;

  /**
   * Our interpreter.
   */
  struct TALER_TESTING_Interpreter *is;

  /**
   * Index to know which web server we check.
   */
  unsigned int index;

  /**
   * Reference to command to the previous set server status operation.
   */
  const char *ref_operation;

  /**
   * Expected method of the pending webhook.
   */
  const char *expected_method;

  /**
   * Expected url of the pending webhook.
   */
  const char *expected_url;

  /**
   * Expected header of the pending webhook.
   */
  const char *expected_header;

  /**
   * Expected body of the pending webhook.
   */
  const char *expected_body;

};


/**
 * Run the command.
 *
 * @param cls closure.
 * @param cmd the command to execute.
 * @param is the interpreter state.
 */
static void
checkserver_run (void *cls,
                 const struct TALER_TESTING_Command *cmd,
                 struct TALER_TESTING_Interpreter *is)
{
  struct CheckState *cs = cls;
  const struct TALER_TESTING_Command *ref;
  const char *url;
  const char *http_method;
  const char *header;
  const void *body;
  const size_t *body_size;

  (void) cmd;
  cs->is = is;
  ref = TALER_TESTING_interpreter_lookup_command (is,
                                                  cs->ref_operation);
  if (NULL == ref)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "ref NULL\n");
    GNUNET_break (0);
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  if (GNUNET_OK !=
      TALER_TESTING_get_trait_urls (ref,
                                    cs->index,
                                    &url))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Trait url does not work\n");
    GNUNET_break (0);
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  if (NULL == url)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Trait for url is NULL!?\n");
    GNUNET_break (0);
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  if (0 != strcmp (cs->expected_url,
                   url))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "URL does not match: `%s' != `%s'\n",
                cs->expected_url,
                url);
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  if (GNUNET_OK !=
      TALER_TESTING_get_trait_http_methods (ref,
                                            cs->index,
                                            &http_method))
    TALER_TESTING_interpreter_fail (is);
  if (0 != strcmp (cs->expected_method,
                   http_method))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "http_method does not match\n");
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  if (GNUNET_OK !=
      TALER_TESTING_get_trait_http_header (ref,
                                           cs->index,
                                           &header))
    TALER_TESTING_interpreter_fail (is);
  if ( ( (NULL == cs->expected_header) && (NULL != header)) ||
       ( (NULL != cs->expected_header) && (NULL == header)) ||
       ( (NULL != cs->expected_header) &&
         (0 != strcmp (cs->expected_header,
                       header)) ) )
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "header does not match: `%s' != `%s'\n",
                cs->expected_header,
                header);
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  if (GNUNET_OK !=
      TALER_TESTING_get_trait_http_body (ref,
                                         cs->index,
                                         &body))
    TALER_TESTING_interpreter_fail (is);
  if (GNUNET_OK !=
      TALER_TESTING_get_trait_http_body_size (ref,
                                              cs->index,
                                              &body_size))
    TALER_TESTING_interpreter_fail (is);
  if ( ( (NULL == cs->expected_body) &&
         (NULL != body) ) ||
       ( (NULL != cs->expected_body) &&
         (NULL == body) ) ||
       ( (NULL != cs->expected_body) &&
         ( (*body_size != strlen (cs->expected_body)) ||
           (0 != memcmp (cs->expected_body,
                         body,
                         *body_size) ) ) ) )
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "body does not match : `%s' and `%.*s'\n",
                cs->expected_body,
                (int) *body_size,
                (const char *) body);
    TALER_TESTING_interpreter_fail (is);
    return;
  }
  TALER_TESTING_interpreter_next (is);
}


/**
 * Free the state of a "checkserver" CMD.
 *
 * @param cls closure.
 * @param cmd command being run.
 */
static void
checkserver_cleanup (void *cls,
                     const struct TALER_TESTING_Command *cmd)
{
  struct CheckState *cs = cls;

  GNUNET_free (cs);
}


struct TALER_TESTING_Command
TALER_TESTING_cmd_checkserver2 (const char *label,
                                const char *ref_operation,
                                unsigned int index,
                                const char *expected_url,
                                const char *expected_method,
                                const char *expected_header,
                                const char *expected_body)
{
  struct CheckState *cs;

  cs = GNUNET_new (struct CheckState);
  cs->ref_operation = ref_operation;
  cs->index = index;
  cs->expected_url = expected_url;
  cs->expected_method = expected_method;
  cs->expected_header = expected_header;
  cs->expected_body = expected_body;

  {
    struct TALER_TESTING_Command cmd = {
      .cls = cs,
      .label = label,
      .run = &checkserver_run,
      .cleanup = &checkserver_cleanup
    };

    return cmd;
  }
}


struct TALER_TESTING_Command
TALER_TESTING_cmd_checkserver (const char *label,
                               const char *ref_operation,
                               unsigned int index)
{
  return TALER_TESTING_cmd_checkserver2 (label,
                                         ref_operation,
                                         index,
                                         "/",
                                         "POST",
                                         "EFEHYJS-Bakery",
                                         "5.0 EUR");
}


/* end of testing_api_cmd_checkserver.c */
