/*
  This file is part of TALER
  (C) 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 Affero General Public License for more
  details.

  You should have received a copy of the GNU Affero General Public License
  along with TALER; see the file COPYING.  If not, see
  <http://www.gnu.org/licenses/>
*/
/**
 * @file taler-merchant-httpd_post-reports-REPORT_ID.c
 * @brief implementation of POST /reports/$REPORT_ID
 * @author Christian Grothoff
 */
#include "taler/platform.h"
#include "taler-merchant-httpd_dispatcher.h"
#include "taler-merchant-httpd_post-reports-REPORT_ID.h"
#include <taler/taler_json_lib.h>


MHD_RESULT
TMH_post_reports_ID (
  const struct TMH_RequestHandler *rh,
  struct MHD_Connection *connection,
  struct TMH_HandlerContext *hc)
{
  const char *report_id_str = hc->infix;
  unsigned long long report_id;
  const char *mime_type;
  struct TALER_MERCHANT_ReportToken report_token;
  struct GNUNET_JSON_Specification spec[] = {
    GNUNET_JSON_spec_fixed_auto ("report_token",
                                 &report_token),
    GNUNET_JSON_spec_end ()
  };
  enum GNUNET_DB_QueryStatus qs;
  char *instance_id;
  char *data_source;

  {
    char dummy;

    if (1 != sscanf (report_id_str,
                     "%llu%c",
                     &report_id,
                     &dummy))
    {
      GNUNET_break_op (0);
      return TALER_MHD_reply_with_error (connection,
                                         MHD_HTTP_BAD_REQUEST,
                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
                                         "report_id");
    }
  }

  {
    enum GNUNET_GenericReturnValue res;

    res = TALER_MHD_parse_json_data (connection,
                                     hc->request_body,
                                     spec);
    if (GNUNET_OK != res)
    {
      GNUNET_break_op (0);
      return (GNUNET_NO == res)
        ? MHD_YES
        : MHD_NO;
    }
  }

  mime_type = MHD_lookup_connection_value (connection,
                                           MHD_HEADER_KIND,
                                           MHD_HTTP_HEADER_ACCEPT);
  if (NULL == mime_type)
    mime_type = "application/json";
  qs = TMH_db->check_report (TMH_db->cls,
                             report_id,
                             &report_token,
                             mime_type,
                             &instance_id,
                             &data_source);
  if (qs < 0)
  {
    GNUNET_break (0);
    return TALER_MHD_reply_with_error (connection,
                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
                                       TALER_EC_GENERIC_DB_FETCH_FAILED,
                                       "check_report");
  }
  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
  {
    return TALER_MHD_reply_with_error (connection,
                                       MHD_HTTP_NOT_FOUND,
                                       TALER_EC_MERCHANT_GENERIC_REPORT_UNKNOWN,
                                       report_id_str);
  }

  {
    struct TMH_MerchantInstance *mi;

    mi = TMH_lookup_instance (instance_id);
    if (NULL == mi)
    {
      /* Strange, we found the report but the instance of the
         report is not known. This should basically be impossible
         modulo maybe some transactional issue where the
         instance was created, the report added *and* triggered
         before this process was able to process the notification
         about the new instance. Wild. */
      GNUNET_break (0);
      return TALER_MHD_reply_with_error (connection,
                                         MHD_HTTP_NOT_FOUND,
                                         TALER_EC_MERCHANT_GENERIC_REPORT_UNKNOWN,
                                         report_id_str);
    }
    /* Rewrite request: force instance to match report */
    mi->rc++;
    if (NULL != hc->instance)
      TMH_instance_decref (hc->instance);
    hc->instance = mi;
  }
  {
    enum GNUNET_GenericReturnValue ret;
    bool is_public; /* ignored: access control never applies for reports */
    char *q;

    /* This rewrites the request: force request handler to match report! */
    q = strchr (data_source,
                '?');
    if (NULL != q)
    {
      /* Terminate URI at '?' for dispatching, parse
         query parameters and add them to this connection */
      *q = '\0';
      for (char *tok = strtok (q + 1,
                               "&");
           NULL != tok;
           tok = strtok (NULL,
                         "&"))
      {
        char *eq;

        eq = strchr (tok,
                     '=');
        if (NULL == eq)
        {
          GNUNET_break (MHD_YES ==
                        MHD_set_connection_value (connection,
                                                  MHD_GET_ARGUMENT_KIND,
                                                  tok,
                                                  NULL));
        }
        else
        {
          *eq = '\0';
          GNUNET_break (MHD_YES ==
                        MHD_set_connection_value (connection,
                                                  MHD_GET_ARGUMENT_KIND,
                                                  tok,
                                                  eq + 1));
        }
      }
    }

    hc->rh = NULL; /* just to make it clear: current one will NOT remain */
    ret = TMH_dispatch_request (hc,
                                data_source,
                                MHD_HTTP_METHOD_GET,
                                0 == strcmp ("admin",
                                             instance_id),
                                &is_public);
    if (GNUNET_OK != ret)
      return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
    GNUNET_break (NULL != hc->rh);
  }
  GNUNET_free (instance_id);
  GNUNET_free (data_source);
  /* MHD will call the main handler again, which will now
     dispatch into the _new_ handler callback we just installed! */
  return MHD_YES;
}
