/*
  This file is part of TALER
  (C) 2023, 2024, 2025 Taler Systems SA

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU Affero 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 taler-merchant-httpd_private-get-statistics-counter-SLUG.c
 * @brief implement GET /statistics-counter/$SLUG/
 * @author Martin Schanzenbach
 */
#include "platform.h"
#include "taler-merchant-httpd_private-get-statistics-counter-SLUG.h"
#include <gnunet/gnunet_json_lib.h>
#include <taler/taler_json_lib.h>


/**
 * Function returning integer-valued statistics.
 * Typically called by `lookup_statistics_counter_by_bucket`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param description description of the statistic
 * @param bucket_start start time of the bucket
 * @param bucket_end end time of the bucket
 * @param bucket_range range of the bucket
 * @param cumulative_number counter value
 */
static void
counter_by_bucket (void *cls,
                   const char *description,
                   struct GNUNET_TIME_Timestamp bucket_start,
                   struct GNUNET_TIME_Timestamp bucket_end,
                   const char *bucket_range,
                   uint64_t cumulative_number)
{
  json_t *root = cls;
  json_t *buckets_array;

  GNUNET_assert (json_is_object (root));
  buckets_array = json_object_get (root,
                                   "buckets");
  GNUNET_assert (NULL != buckets_array);
  GNUNET_assert (json_is_array (buckets_array));
  GNUNET_assert (
    0 ==
    json_array_append_new (
      buckets_array,
      GNUNET_JSON_PACK (
        GNUNET_JSON_pack_timestamp (
          "start_time",
          bucket_start),
        GNUNET_JSON_pack_timestamp (
          "end_time",
          bucket_end),
        GNUNET_JSON_pack_string (
          "range",
          bucket_range),
        GNUNET_JSON_pack_uint64 (
          "cumulative_counter",
          cumulative_number))));
  if (NULL == json_object_get (root,
                               "buckets_description"))
  {
    GNUNET_assert (
      0 ==
      json_object_set_new (root,
                           "buckets_description",
                           json_string (description)));
  }
}


/**
 * Function returning integer-valued statistics for a time interval.
 * Called by `lookup_statistics_counter_by_interval`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param description description of the statistic
 * @param bucket_start start time of the interval
 * @param cumulative_number counter value
 */
static void
counter_by_interval (void *cls,
                     const char *description,
                     struct GNUNET_TIME_Timestamp bucket_start,
                     uint64_t cumulative_number)
{
  json_t *root = cls;
  json_t *intervals_array;

  GNUNET_assert (json_is_object (root));
  intervals_array = json_object_get (root,
                                     "intervals");
  GNUNET_assert (NULL != intervals_array);
  GNUNET_assert (json_is_array (intervals_array));
  GNUNET_assert (
    0 ==
    json_array_append_new (
      intervals_array,
      GNUNET_JSON_PACK (
        GNUNET_JSON_pack_timestamp (
          "start_time",
          bucket_start),
        GNUNET_JSON_pack_uint64 (
          "cumulative_counter",
          cumulative_number))));
  if (NULL == json_object_get (root,
                               "intervals_description"))
  {
    GNUNET_assert (
      0 ==
      json_object_set_new (root,
                           "intervals_description",
                           json_string (description)));
  }
}


/**
 * Handle a GET "/statistics-counter/$SLUG" request.
 *
 * @param rh context of the handler
 * @param connection the MHD connection to handle
 * @param[in,out] hc context with further information about the request
 * @return MHD result code
 */
MHD_RESULT
TMH_private_get_statistics_counter_SLUG (const struct TMH_RequestHandler *rh,
                                         struct MHD_Connection *connection,
                                         struct TMH_HandlerContext *hc)
{
  struct TMH_MerchantInstance *mi = hc->instance;
  json_t *root;
  bool get_buckets = true;
  bool get_intervals = true;

  GNUNET_assert (NULL != mi);
  {
    const char *filter;

    filter = MHD_lookup_connection_value (connection,
                                          MHD_GET_ARGUMENT_KIND,
                                          "by");
    if (NULL != filter)
    {
      if (0 == strcasecmp (filter,
                           "bucket"))
        get_intervals = false;
      else if (0 == strcasecmp (filter,
                                "interval"))
        get_buckets = false;
      else if (0 != strcasecmp (filter,
                                "any"))
      {
        GNUNET_break_op (0);
        return TALER_MHD_reply_with_error (
          connection,
          MHD_HTTP_INTERNAL_SERVER_ERROR,
          TALER_EC_GENERIC_PARAMETER_MALFORMED,
          "by");
      }
    }
  }
  root = GNUNET_JSON_PACK (
    GNUNET_JSON_pack_array_steal ("intervals",
                                  json_array ()),
    GNUNET_JSON_pack_array_steal ("buckets",
                                  json_array ()));
  if (get_buckets)
  {
    enum GNUNET_DB_QueryStatus qs;

    qs = TMH_db->lookup_statistics_counter_by_bucket (
      TMH_db->cls,
      mi->settings.id,
      hc->infix,
      &counter_by_bucket,
      root);
    if (0 > qs)
    {
      GNUNET_break (0);
      json_decref (root);
      return TALER_MHD_reply_with_error (
        connection,
        MHD_HTTP_INTERNAL_SERVER_ERROR,
        TALER_EC_GENERIC_DB_FETCH_FAILED,
        "lookup_statistics_counter_by_bucket");
    }
  }
  if (get_intervals)
  {
    enum GNUNET_DB_QueryStatus qs;

    qs = TMH_db->lookup_statistics_counter_by_interval (
      TMH_db->cls,
      mi->settings.id,
      hc->infix,
      &counter_by_interval,
      root);
    if (0 > qs)
    {
      GNUNET_break (0);
      json_decref (root);
      return TALER_MHD_reply_with_error (
        connection,
        MHD_HTTP_INTERNAL_SERVER_ERROR,
        TALER_EC_GENERIC_DB_FETCH_FAILED,
        "lookup_statistics_counter_by_interval");
    }
  }
  return TALER_MHD_reply_json (connection,
                               root,
                               MHD_HTTP_OK);
}


/* end of taler-merchant-httpd_private-get-statistics-counter-SLUG.c */
