/*
 * Copyright 2009-present MongoDB, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef JSON_TEST_OPERATIONS_H
#define JSON_TEST_OPERATIONS_H

struct _json_test_config_t;

#include <common-thread-private.h>
#include <mongoc/mongoc-thread-private.h>

#include <mongoc/mongoc-client.h>
#include <mongoc/mongoc-uri.h>

#include <mock_server/sync-queue.h>

struct _json_test_ctx_t;

typedef struct {
   struct _json_test_ctx_t *ctx;
   bson_thread_t thread;
   sync_queue_t *queue;
   bson_mutex_t mutex;
   mongoc_cond_t cond;
   bool shutdown_requested;
} json_test_worker_thread_t;

typedef struct _json_test_ctx_t {
   const struct _json_test_config_t *config;
   uint32_t n_events;
   bson_t events;
   mongoc_uri_t *test_framework_uri;
   mongoc_client_session_t *sessions[2];
   bson_t lsids[2];
   bool acknowledged;
   bool verbose;
   bool has_sessions;
   mongoc_client_t *client;
   mongoc_database_t *db;
   mongoc_collection_t *collection;
   mongoc_change_stream_t *change_stream;
   /* Sessions tests check the most recently sent two lsid's */
   bson_t *sent_lsids[2];
   bson_mutex_t mutex;
   /* The total number of times a server description was marked unknown. */
   int64_t total_ServerMarkedUnknownEvent;
   /* How many were accounted for in the test. */
   int64_t measured_ServerMarkedUnknownEvent;
   /* How many connection generation increments were accounted for in the test.
    */
   int64_t measured_PoolClearedEvent;
   mongoc_host_list_t primary_host;

   int64_t total_PrimaryChangedEvent;
   int64_t measured_PrimaryChangedEvent;

   json_test_worker_thread_t *worker_threads[2];
} json_test_ctx_t;

mongoc_client_session_t *
session_from_name(json_test_ctx_t *ctx, const char *session_name);

void
json_test_ctx_init(json_test_ctx_t *ctx,
                   const bson_t *test,
                   mongoc_client_t *client,
                   mongoc_database_t *db,
                   mongoc_collection_t *collection,
                   const struct _json_test_config_t *config);

void
json_test_ctx_end_sessions(json_test_ctx_t *ctx);

void
json_test_ctx_cleanup(json_test_ctx_t *ctx);

typedef bool (*json_test_operation_cb_t)(json_test_ctx_t *ctx, const bson_t *test, const bson_t *operation);

typedef void (*json_test_cb_t)(json_test_ctx_t *ctx, const bson_t *test);

bool
json_test_operation(json_test_ctx_t *ctx,
                    const bson_t *test,
                    const bson_t *operation,
                    mongoc_collection_t *collection,
                    mongoc_client_session_t *session,
                    bson_t *reply);

void
json_test_operations(json_test_ctx_t *ctx, const bson_t *test);

void
check_result(
   const bson_t *test, const bson_t *operation, bool succeeded, const bson_value_t *result, const bson_error_t *error);

json_test_worker_thread_t *
worker_thread_new(json_test_ctx_t *ctx);

void
worker_thread_destroy(json_test_worker_thread_t *wt);

#endif
