/**
 *
 * 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 <assert.h>
#include <node_api.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "lib/mutex.h"
#include "macro/mark.h"
#include "rte_runtime/metadata/metadata.h"
#include "rte_runtime/rte/rte.h"

#define EXPORT_FUNC(env, exports, func)                \
  do {                                                 \
    rte_nodejs_export_func(env, exports, #func, func); \
  } while (0)

#define ASSERT_IF_NAPI_FAIL(expr, fmt, ...) \
  do {                                      \
    if (!(expr)) {                          \
      ZF_LOGE(fmt, ##__VA_ARGS__);          \
      /* NOLINTNEXTLINE */                  \
      assert(0 && "Should not happen.");    \
      /* NOLINTNEXTLINE */                  \
      exit(-1);                             \
    }                                       \
  } while (0)

#define CHECK_IF_NAPI_FAIL(expr, fmt, ...)            \
  do {                                                \
    if (!(expr)) {                                    \
      rte_nodejs_report_and_clear_error(env, status); \
      ZF_LOGE(fmt, ##__VA_ARGS__);                    \
      /* NOLINTNEXTLINE */                            \
      assert(0 && "Should not happen.");              \
    }                                                 \
  } while (0)

#define GOTO_LABEL_IF_NAPI_FAIL(label, expr, fmt, ...) \
  do {                                                 \
    if (!(expr)) {                                     \
      rte_nodejs_report_and_clear_error(env, status);  \
      ZF_LOGE(fmt, ##__VA_ARGS__);                     \
      goto label;                                      \
    }                                                  \
  } while (0)

#define RETURN_UNDEFINED_IF_NAPI_FAIL(expr, fmt, ...) \
  do {                                                \
    if (!(expr)) {                                    \
      rte_nodejs_report_and_clear_error(env, status); \
      ZF_LOGE(fmt, ##__VA_ARGS__);                    \
      /* NOLINTNEXTLINE */                            \
      assert(0 && "Should not happen.");              \
      return UNDEFINED(env);                          \
    }                                                 \
  } while (0)

AGORA_RTE_PRIVATE_API napi_value UNDEFINED(napi_env env);

AGORA_RTE_PRIVATE_API bool is_undefined(napi_env env, napi_value val);

AGORA_RTE_PRIVATE_API bool is_string(napi_env env, napi_value val);

AGORA_RTE_PRIVATE_API bool is_object(napi_env env, napi_value val);

AGORA_RTE_PRIVATE_API bool is_array(napi_env env, napi_value val);

AGORA_RTE_PRIVATE_API bool is_buffer(napi_env env, napi_value val);

AGORA_RTE_PRIVATE_API bool rte_nodejs_get_args(napi_env env,
                                               napi_callback_info info,
                                               napi_value* args, size_t argc);

AGORA_RTE_PRIVATE_API bool rte_nodejs_get_loc(napi_env env, napi_value val,
                                              rte_loc_t* loc);

AGORA_RTE_PRIVATE_API bool rte_nodejs_get_str(napi_env env, napi_value val,
                                              rte_string_t* str);

AGORA_RTE_PRIVATE_API void* rte_nodejs_get_buffer(napi_env env, napi_value val,
                                                  size_t* len_in_byte);

AGORA_RTE_PRIVATE_API bool rte_nodejs_get_arr_len(napi_env env, napi_value val,
                                                  uint32_t* arr_len);

AGORA_RTE_PRIVATE_API bool rte_nodejs_get_arr(napi_env env, napi_value val,
                                              napi_value* arr,
                                              uint32_t arr_len);

AGORA_RTE_PRIVATE_API void rte_nodejs_export_func(napi_env env,
                                                  napi_value exports,
                                                  const char* func_name,
                                                  napi_callback func);

AGORA_RTE_PRIVATE_API void rte_nodejs_report_and_clear_error_(
    napi_env env, napi_status status, const char* func, int line);

#define rte_nodejs_report_and_clear_error(env, status) \
  rte_nodejs_report_and_clear_error_(env, status, __FUNCTION__, __LINE__)

AGORA_RTE_PRIVATE_API napi_value rte_nodejs_create_new_js_object_and_wrap(
    napi_env env, napi_ref constructor_ref, void* bridge_obj,
    napi_finalize finalizer, napi_ref* bridge_weak_ref);

AGORA_RTE_PRIVATE_API napi_value rte_nodejs_get_property(napi_env env,
                                                         napi_value self,
                                                         const char* name);
