/*
     This file is part of anastasis-gtk.
     Copyright (C) 2022 Anastasis SARL

     Anastasis 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.

     Anastasis 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 Anastasis; see the file COPYING.  If not, write to the
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     Boston, MA 02110-1301, USA.
*/

/**
 * @file src/anastasis/anastasis-gtk_handle-add-provider.c
 * @brief Dialog to add a provider during recovery
 * @author Christian Grothoff
 */
#include <gnunet/gnunet_util_lib.h>
#include "anastasis_gtk_util.h"
#include "anastasis-gtk_action.h"
#include "anastasis-gtk_helper.h"
#include <jansson.h>
#include <microhttpd.h>

/**
 * State data for the provider, NULL if none is available.
 */
static json_t *pstate;

/**
 * Current /config operation, or NULL if none.
 */
static struct ANASTASIS_ConfigOperation *co;


/**
 * Function called with the result of a /config request.
 * Note that an HTTP status of #MHD_HTTP_OK is no guarantee
 * that @a acfg is non-NULL. @a acfg is non-NULL only if
 * the server provided an acceptable response.
 *
 * @param cls closure with our `GtkBuilder *`
 * @param acfg configuration obtained, NULL if we could not parse it
 */
static void
config_cb (void *cls,
           const struct ANASTASIS_Config *acfg)
{
  GtkBuilder *builder = GTK_BUILDER (cls);
  GtkWidget *button;
  json_t *methods_list;
  GtkLabel *l;

  co = NULL;
  l = GTK_LABEL (gtk_builder_get_object (builder,
                                         "error_label"));
  if (MHD_HTTP_OK != acfg->http_status)
  {
    char *msg;

    if (0 == acfg->http_status)
      GNUNET_asprintf (&msg,
                       "Provider URL invalid (no response)");
    else
      GNUNET_asprintf (&msg,
                       "Provider URL invalid (HTTP status %u)",
                       acfg->http_status);
    gtk_widget_show (GTK_WIDGET (l));
    gtk_label_set_text (l,
                        msg);
    free (msg);
    return;
  }
  methods_list = json_array ();
  GNUNET_assert (NULL != methods_list);
  for (unsigned int i = 0; i<acfg->details.ok.methods_length; i++)
  {
    const struct ANASTASIS_AuthorizationMethodConfig *method
      = &acfg->details.ok.methods[i];
    json_t *mj = GNUNET_JSON_PACK (
      GNUNET_JSON_pack_string ("type",
                               method->type),
      TALER_JSON_pack_amount ("usage_fee",
                              &method->usage_fee));

    GNUNET_assert (0 ==
                   json_array_append_new (methods_list,
                                          mj));
  }
  pstate = GNUNET_JSON_PACK (
    GNUNET_JSON_pack_array_steal ("methods",
                                  methods_list),
    TALER_JSON_pack_amount ("annual_fee",
                            &acfg->details.ok.annual_fee),
    TALER_JSON_pack_amount ("truth_upload_fee",
                            &acfg->details.ok.truth_upload_fee),
    TALER_JSON_pack_amount ("liability_limit",
                            &acfg->details.ok.liability_limit),
    GNUNET_JSON_pack_string ("business_name",
                             acfg->details.ok.business_name),
    GNUNET_JSON_pack_string ("status",
                             "enabled"),
    GNUNET_JSON_pack_uint64 ("http_status",
                             MHD_HTTP_OK),
    GNUNET_JSON_pack_uint64 ("storage_limit_in_megabytes",
                             acfg->details.ok.storage_limit_in_megabytes),
    GNUNET_JSON_pack_data_auto ("provider_salt",
                                &acfg->details.ok.provider_salt),
    GNUNET_JSON_pack_uint64 ("http_status",
                             acfg->http_status));
  button = GTK_WIDGET (gtk_builder_get_object (builder,
                                               "add_button"));
  gtk_widget_set_sensitive (button,
                            true);
  gtk_widget_hide (GTK_WIDGET (l));
}


/**
 * Function called when the user edits the URL in the "add_provider"
 * dialog. Updates the visibility of the 'apply/add' button.
 *
 * @param entry the entry that changed
 * @param user_data our `GtkBuilder *`
 */
void
add_provider_url_entry_changed_cb (GtkEntry *entry,
                                   gpointer user_data)
{
  GtkBuilder *builder = GTK_BUILDER (user_data);
  GtkWidget *button;
  const char *url;

  json_decref (pstate);
  pstate = NULL;
  if (NULL != co)
  {
    ANASTASIS_config_cancel (co);
    co = NULL;
  }
  button = GTK_WIDGET (gtk_builder_get_object (builder,
                                               "add_button"));
  gtk_widget_set_sensitive (button,
                            false);
  url = gtk_entry_get_text (entry);
  if ( (0 == strncasecmp (url,
                          "http://",
                          strlen ("http://"))) ||
       (0 == strncasecmp (url,
                          "https://",
                          strlen ("https://"))) )
  {
    co = ANASTASIS_get_config (AG_ctx,
                               url,
                               &config_cb,
                               builder);
    GNUNET_break (NULL != co);
  }
}


/**
 * Function called from the edit-provider dialog upon completion.
 *
 * @param dialog the pseudonym selection dialog
 * @param response_id response code from the dialog
 * @param user_data the builder of the dialog
 */
void
add_provider_dialog_response_cb (GtkDialog *dialog,
                                 gint response_id,
                                 gpointer user_data)
{
  GtkBuilder *builder = GTK_BUILDER (user_data);
  GtkEntry *entry;
  const char *url;
  json_t *ap;

  if (NULL != co)
  {
    ANASTASIS_config_cancel (co);
    co = NULL;
  }
  if (GTK_RESPONSE_APPLY != response_id)
  {
    gtk_widget_destroy (GTK_WIDGET (dialog));
    g_object_unref (G_OBJECT (builder));
    json_decref (pstate);
    pstate = NULL;
    return;
  }
  if (NULL == pstate)
  {
    GNUNET_break (0);
    return;
  }
  ap = json_object_get (AG_redux_state,
                        "authentication_providers");
  if (NULL == ap)
  {
    GNUNET_break (0);
    return;
  }
  entry = GTK_ENTRY (gtk_builder_get_object (builder,
                                             "url_entry"));
  url = gtk_entry_get_text (entry);
  ANASTASIS_policy_discovery_more (AG_pd,
                                   url,
                                   pstate);
  GNUNET_break (0 ==
                json_object_set_new (ap,
                                     url,
                                     pstate));
  pstate = NULL;
  gtk_widget_destroy (GTK_WIDGET (dialog));
  g_object_unref (G_OBJECT (builder));
}


/**
 * Callback invoked if the the "Add"-provider button is clicked.
 *
 * @param object
 * @param user_data unused
 */
void
anastasis_gtk_add_provider_button_clicked_cb (GtkButton *object,
                                              gpointer user_data)
{
  GtkWidget *ad;
  GtkBuilder *builder;
  GtkWidget *toplevel;

  if (NULL == AG_pd)
  {
    GNUNET_break (0);
    return;
  }
  builder = ANASTASIS_GTK_get_new_builder (
    ANASTASIS_GTK_project_data (),
    "anastasis_gtk_add_provider.glade",
    NULL);
  if (NULL == builder)
  {
    GNUNET_break (0);
    return;
  }
  ad = GTK_WIDGET (gtk_builder_get_object (builder,
                                           "add_provider_dialog"));
  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (object));
  gtk_window_set_transient_for (GTK_WINDOW (ad),
                                GTK_WINDOW (toplevel));
  gtk_window_present (GTK_WINDOW (ad));
}
