/* gcc example-command-monitoring.c -o example-command-monitoring \
 *     $(pkg-config --cflags --libs libmongoc-1.0) */

/* ./example-command-monitoring [CONNECTION_STRING] */

#include <mongoc/mongoc.h>

#include <stdio.h>


typedef struct {
   int started;
   int succeeded;
   int failed;
} stats_t;


void
command_started(const mongoc_apm_command_started_t *event)
{
   char *s;

   s = bson_as_relaxed_extended_json(mongoc_apm_command_started_get_command(event), NULL);
   printf("Command %s started on %s:\n%s\n\n",
          mongoc_apm_command_started_get_command_name(event),
          mongoc_apm_command_started_get_host(event)->host,
          s);

   ((stats_t *)mongoc_apm_command_started_get_context(event))->started++;

   bson_free(s);
}


void
command_succeeded(const mongoc_apm_command_succeeded_t *event)
{
   char *s;

   s = bson_as_relaxed_extended_json(mongoc_apm_command_succeeded_get_reply(event), NULL);
   printf("Command %s succeeded:\n%s\n\n", mongoc_apm_command_succeeded_get_command_name(event), s);

   ((stats_t *)mongoc_apm_command_succeeded_get_context(event))->succeeded++;

   bson_free(s);
}


void
command_failed(const mongoc_apm_command_failed_t *event)
{
   bson_error_t error;

   mongoc_apm_command_failed_get_error(event, &error);
   printf("Command %s failed:\n\"%s\"\n\n", mongoc_apm_command_failed_get_command_name(event), error.message);

   ((stats_t *)mongoc_apm_command_failed_get_context(event))->failed++;
}


int
main(int argc, char *argv[])
{
   mongoc_client_t *client;
   mongoc_apm_callbacks_t *callbacks;
   stats_t stats = {0};
   mongoc_collection_t *collection;
   bson_error_t error;
   const char *uri_string = "mongodb://127.0.0.1/?appname=cmd-monitoring-example";
   mongoc_uri_t *uri;
   const char *collection_name = "test";
   bson_t *docs[2];

   mongoc_init();

   if (argc > 1) {
      uri_string = argv[1];
   }

   uri = mongoc_uri_new_with_error(uri_string, &error);
   if (!uri) {
      fprintf(stderr,
              "failed to parse URI:\n"
              "error message: %s\n",
              error.message);
      return EXIT_FAILURE;
   }

   client = mongoc_client_new_from_uri(uri);
   if (!client) {
      return EXIT_FAILURE;
   }

   mongoc_client_set_error_api(client, 2);
   callbacks = mongoc_apm_callbacks_new();
   mongoc_apm_set_command_started_cb(callbacks, command_started);
   mongoc_apm_set_command_succeeded_cb(callbacks, command_succeeded);
   mongoc_apm_set_command_failed_cb(callbacks, command_failed);
   mongoc_client_set_apm_callbacks(client, callbacks, (void *)&stats /* context pointer */);

   collection = mongoc_client_get_collection(client, "test", collection_name);
   mongoc_collection_drop(collection, NULL);

   docs[0] = BCON_NEW("_id", BCON_INT32(0));
   docs[1] = BCON_NEW("_id", BCON_INT32(1));
   mongoc_collection_insert_many(collection, (const bson_t **)docs, 2, NULL, NULL, NULL);

   /* duplicate key error on the second insert */
   mongoc_collection_insert_one(collection, docs[0], NULL, NULL, NULL);

   mongoc_collection_destroy(collection);
   mongoc_apm_callbacks_destroy(callbacks);
   mongoc_uri_destroy(uri);
   mongoc_client_destroy(client);

   printf("started: %d\nsucceeded: %d\nfailed: %d\n", stats.started, stats.succeeded, stats.failed);

   bson_destroy(docs[0]);
   bson_destroy(docs[1]);

   mongoc_cleanup();

   return EXIT_SUCCESS;
}
