/*
  This file is part of TALER
  Copyright (C) 2025 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_api_cmd_patch_unit.c
 * @brief command to test PATCH /private/units/$ID
 * @author Bohdan Potuzhnyi
 */
#include "platform.h"
#include <taler/taler_testing_lib.h>
#include "taler_merchant_service.h"
#include "taler_merchant_testing_lib.h"


/**
 * State for a PATCH /private/units command.
 */
struct PatchUnitState
{
  /**
   * In-flight request handle.
   */
  struct TALER_MERCHANT_UnitPatchHandle *uph;

  /**
   * Interpreter context.
   */
  struct TALER_TESTING_Interpreter *is;

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

  /**
   * Unit identifier.
   */
  const char *unit_id;

  /**
   * Optional new long label.
   */
  const char *unit_name_long;

  /**
   * Optional new short label.
   */
  const char *unit_name_short;

  /**
   * Optional long label translations.
   */
  json_t *unit_name_long_i18n;

  /**
   * Optional short label translations.
   */
  json_t *unit_name_short_i18n;

  /**
   * Whether a new fractional flag was provided.
   */
  bool have_unit_allow_fraction;

  /**
   * New fractional flag value.
   */
  bool unit_allow_fraction;

  /**
   * Whether a new precision level was provided.
   */
  bool have_unit_precision_level;

  /**
   * New precision level.
   */
  uint32_t unit_precision_level;

  /**
   * Whether a new active flag was provided.
   */
  bool have_unit_active;

  /**
   * New active flag value.
   */
  bool unit_active;

  /**
   * Expected HTTP status.
   */
  unsigned int http_status;
};


/**
 * Completion callback for PATCH /private/units.
 */
static void
patch_unit_cb (void *cls,
               const struct TALER_MERCHANT_HttpResponse *hr)
{
  struct PatchUnitState *pus = cls;

  pus->uph = NULL;
  if (pus->http_status != hr->http_status)
  {
    TALER_TESTING_unexpected_status_with_body (pus->is,
                                               hr->http_status,
                                               pus->http_status,
                                               hr->reply);
    return;
  }
  TALER_TESTING_interpreter_next (pus->is);
}


/**
 * Issue the PATCH request.
 */
static void
patch_unit_run (void *cls,
                const struct TALER_TESTING_Command *cmd,
                struct TALER_TESTING_Interpreter *is)
{
  struct PatchUnitState *pus = cls;
  const bool *allow_ptr = pus->have_unit_allow_fraction
                          ? &pus->unit_allow_fraction
                          : NULL;
  const uint32_t *precision_ptr = pus->have_unit_precision_level
                                  ? &pus->unit_precision_level
                                  : NULL;
  const bool *active_ptr = pus->have_unit_active
                           ? &pus->unit_active
                           : NULL;

  pus->is = is;
  pus->uph = TALER_MERCHANT_unit_patch (
    TALER_TESTING_interpreter_get_context (is),
    pus->merchant_url,
    pus->unit_id,
    pus->unit_name_long,
    pus->unit_name_short,
    pus->unit_name_long_i18n,
    pus->unit_name_short_i18n,
    allow_ptr,
    precision_ptr,
    active_ptr,
    &patch_unit_cb,
    pus);
  if (NULL == pus->uph)
  {
    GNUNET_break (0);
    TALER_TESTING_interpreter_fail (is);
  }
}


/**
 * Provide traits to other commands.
 */
static enum GNUNET_GenericReturnValue
patch_unit_traits (void *cls,
                   const void **ret,
                   const char *trait,
                   unsigned int index)
{
  struct PatchUnitState *pus = cls;
  struct TALER_TESTING_Trait traits[] = {
    TALER_TESTING_make_trait_unit_id (pus->unit_id),
    TALER_TESTING_make_trait_unit_name_long (pus->unit_name_long),
    TALER_TESTING_make_trait_unit_name_short (pus->unit_name_short),
    TALER_TESTING_make_trait_unit_name_long_i18n (pus->unit_name_long_i18n),
    TALER_TESTING_make_trait_unit_name_short_i18n (pus->unit_name_short_i18n),
    TALER_TESTING_make_trait_unit_allow_fraction (
      pus->have_unit_allow_fraction
      ? &pus->unit_allow_fraction
      : NULL),
    TALER_TESTING_make_trait_unit_precision_level (
      pus->have_unit_precision_level
      ? &pus->unit_precision_level
      : NULL),
    TALER_TESTING_make_trait_unit_active (
      pus->have_unit_active
      ? &pus->unit_active
      : NULL),
    TALER_TESTING_trait_end ()
  };

  return TALER_TESTING_get_trait (traits,
                                  ret,
                                  trait,
                                  index);
}


/**
 * Cleanup.
 */
static void
patch_unit_cleanup (void *cls,
                    const struct TALER_TESTING_Command *cmd)
{
  struct PatchUnitState *pus = cls;

  if (NULL != pus->uph)
  {
    TALER_MERCHANT_unit_patch_cancel (pus->uph);
    pus->uph = NULL;
  }
  if (NULL != pus->unit_name_long_i18n)
    json_decref (pus->unit_name_long_i18n);
  if (NULL != pus->unit_name_short_i18n)
    json_decref (pus->unit_name_short_i18n);
  GNUNET_free (pus);
}


struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_unit (const char *label,
                                       const char *merchant_url,
                                       const char *unit_id,
                                       const char *unit_name_long,
                                       const char *unit_name_short,
                                       json_t *unit_name_long_i18n,
                                       json_t *unit_name_short_i18n,
                                       const bool unit_allow_fraction,
                                       const uint32_t unit_precision_level,
                                       const bool unit_active,
                                       unsigned int http_status)
{
  struct PatchUnitState *pus;

  pus = GNUNET_new (struct PatchUnitState);
  pus->merchant_url = merchant_url;
  pus->unit_id = unit_id;
  pus->unit_name_long = unit_name_long;
  pus->unit_name_short = unit_name_short;
  pus->unit_name_long_i18n = unit_name_long_i18n;
  pus->unit_name_short_i18n = unit_name_short_i18n;
  pus->unit_allow_fraction = unit_allow_fraction;
  pus->have_unit_allow_fraction = true;
  pus->unit_precision_level = unit_precision_level;
  pus->have_unit_precision_level = true;
  pus->unit_active = unit_active;
  pus->have_unit_active = true;
  pus->http_status = http_status;
  {
    struct TALER_TESTING_Command cmd = {
      .cls = pus,
      .label = label,
      .run = &patch_unit_run,
      .cleanup = &patch_unit_cleanup,
      .traits = &patch_unit_traits
    };

    return cmd;
  }
}


/* end of testing_api_cmd_patch_unit.c */
