/**
 *
 * Agora Real Time Engagement
 * Created by Wei Hu in 2021-09.
 * Copyright (c) 2022 Agora IO. All rights reserved.
 *
 */
#pragma once

#include "rte_config.h"

#include <node_api.h>

#include "lib/mutex.h"
#include "lib/rwlock.h"
#include "lib/shared_ptr.h"
#include "lib/signature.h"
#include "rte_runtime/rte/rte.h"
#include "rte_runtime/sanitizer/thread_check.h"

#define RTE_NODEJS_RTE_SIGNATURE 0x180B00AACEEF06E0U

#define RTE_NODEJS_LOCK_RTE_FROM_CLOSE(env, rte_bridge)                \
  do {                                                                 \
    rte_rwlock_lock((rte_bridge)->is_close_lock, 1);                   \
    if ((rte_bridge)->is_close == true) {                              \
      rte_rwlock_unlock((rte_bridge)->is_close_lock, 1);               \
      napi_status status =                                             \
          napi_throw_error(env, "ECLOSE", "Graph is closing");         \
      ASSERT_IF_NAPI_FAIL(status == napi_ok,                           \
                          "Failed to throw JS exception: %d", status); \
      goto done;                                                       \
    }                                                                  \
  } while (0)

#define RTE_NODEJS_UNLOCK_RTE_FROM_CLOSE(rte_bridge)   \
  do {                                                 \
    rte_rwlock_unlock((rte_bridge)->is_close_lock, 1); \
  } while (0)

typedef struct rte_nodejs_rte_t {
  rte_signature_t signature;

  rte_rwlock_t* is_close_lock;
  bool is_close;

  // Currently, the JavaScript callback function of sendXxx will be recorded in
  // the following list. In theory, these JS callbacks will be released when
  // they are done, but if the graph system (engine/group/extension) is
  // destroyed before the JS callback is done, we can destroy the remaining
  // items in this list to prevent memory leaks of threadsafe functions, and
  // prevent nodejs from exiting.
  //
  // Important! Note that all the operations for the following list should be
  // done in the JS main thread, so we don't need to have a mutex lock for this
  // list.
  rte_list_t tsfns;  // rte_nodejs_threadsafe_function_t

  // Used to determine the timing of destroying this rte bridge.
  rte_sharedptr_t* shared_ptr;

  rte_t* c_rte;     // Point to the corresponding C rte.
  napi_ref js_ref;  // Point to the corresponding JS rte.

  rte_sanitizer_thread_check_t thread_check;
} rte_nodejs_rte_t;

AGORA_RTE_PRIVATE_API bool rte_nodejs_rte_check_integrity(
    rte_nodejs_rte_t* self, bool check_thread);

AGORA_RTE_API napi_value rte_nodejs_rte_module_init(napi_env env,
                                                    napi_value exports);

AGORA_RTE_API napi_value rte_nodejs_rte_wrap(napi_env env, rte_t* rte,
                                             rte_nodejs_rte_t** out_rte_bridge);
