/*
  This file is part of TALER
  (C) 2014-2023 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_post-orders-ID-paid.c
 * @brief handling of POST /orders/$ID/paid requests
 * @author Christian Grothoff
 */
#include "platform.h"
#include <taler/taler_dbevents.h>
#include <taler/taler_signatures.h>
#include <taler/taler_json_lib.h>
#include <taler/taler_exchange_service.h>
#include "taler-merchant-httpd_helper.h"
#include "taler-merchant-httpd_post-orders-ID-paid.h"


/**
 * Use database to notify other clients about the
 * session being captured.
 *
 * @param hc http context
 * @param session_id the captured session
 * @param fulfillment_url the URL that is now paid for by @a session_id
 */
static void
trigger_session_notification (struct TMH_HandlerContext *hc,
                              const char *session_id,
                              const char *fulfillment_url)
{
  struct TMH_SessionEventP session_eh = {
    .header.size = htons (sizeof (session_eh)),
    .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
    .merchant_pub = hc->instance->merchant_pub
  };

  GNUNET_CRYPTO_hash (session_id,
                      strlen (session_id),
                      &session_eh.h_session_id);
  GNUNET_CRYPTO_hash (fulfillment_url,
                      strlen (fulfillment_url),
                      &session_eh.h_fulfillment_url);
  TMH_db->event_notify (TMH_db->cls,
                        &session_eh.header,
                        NULL,
                        0);
}


MHD_RESULT
TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh,
                         struct MHD_Connection *connection,
                         struct TMH_HandlerContext *hc)
{
  const char *order_id = hc->infix;
  struct TALER_MerchantSignatureP merchant_sig;
  const char *session_id;
  struct TALER_PrivateContractHashP hct;
  char *fulfillment_url;
  enum GNUNET_DB_QueryStatus qs;
  bool refunded;

  {
    struct GNUNET_JSON_Specification spec[] = {
      GNUNET_JSON_spec_fixed_auto ("sig",
                                   &merchant_sig),
      GNUNET_JSON_spec_fixed_auto ("h_contract",
                                   &hct),
      GNUNET_JSON_spec_string ("session_id",
                               &session_id),
      GNUNET_JSON_spec_end ()
    };
    enum GNUNET_GenericReturnValue res;

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

  if (GNUNET_OK !=
      TALER_merchant_pay_verify (&hct,
                                 &hc->instance->merchant_pub,
                                 &merchant_sig))
  {
    GNUNET_break_op (0);
    return TALER_MHD_reply_with_error (connection,
                                       MHD_HTTP_FORBIDDEN,
                                       TALER_EC_MERCHANT_POST_ORDERS_ID_PAID_COIN_SIGNATURE_INVALID,
                                       NULL);
  }

  TMH_db->preflight (TMH_db->cls);

  qs = TMH_db->update_contract_session (TMH_db->cls,
                                        hc->instance->settings.id,
                                        &hct,
                                        session_id,
                                        &fulfillment_url,
                                        &refunded);
  switch (qs)
  {
  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                "Unknown order id given: `%s'\n",
                order_id);
    return TALER_MHD_reply_with_error (connection,
                                       MHD_HTTP_NOT_FOUND,
                                       TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
                                       NULL);
  case GNUNET_DB_STATUS_HARD_ERROR:
    GNUNET_break (0);
    return TALER_MHD_reply_with_error (connection,
                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
                                       TALER_EC_GENERIC_DB_STORE_FAILED,
                                       "update_contract_session");
  case GNUNET_DB_STATUS_SOFT_ERROR:
    GNUNET_break (0);
    return TALER_MHD_reply_with_error (connection,
                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
                                       TALER_EC_GENERIC_DB_STORE_FAILED,
                                       "update_contract_session");
  case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    /* continued below */
    break;
  }

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Marking contract %s with %s/%s as paid\n",
              order_id,
              session_id,
              fulfillment_url);

  /* Wake everybody up who waits for this fulfillment_url and session_id */
  if ( (NULL != fulfillment_url) &&
       (NULL != session_id) )
    trigger_session_notification (hc,
                                  session_id,
                                  fulfillment_url);
  /*Trigger webhook */
  /*Commented out until its purpose is defined
    {
    enum GNUNET_DB_QueryStatus qs;
    json_t *jhook;

    jhook = GNUNET_JSON_PACK (
      GNUNET_JSON_pack_object_incref ("contract_terms",
                                      contract_terms),
      GNUNET_JSON_pack_string ("order_id",
                               order_id)
    );
    GNUNET_assert (NULL != jhook);
    qs = TMH_trigger_webhook (hc->instance->settings.id,
                              "paid",
                              jhook);
    json_decref (jhook);
    if (qs < 0)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "Failed to init the webhook for contract %s with %s/%s as paid\n",
                  order_id,
                  session_id,
                  fulfillment_url);
    }
  }*/
  GNUNET_free (fulfillment_url);

  return TALER_MHD_REPLY_JSON_PACK (
    connection,
    MHD_HTTP_OK,
    GNUNET_JSON_pack_bool ("refunded",
                           refunded));
}


/* end of taler-merchant-httpd_post-orders-ID-paid.c */
