#ifndef EMNAPI_INCLUDE_EMNAPI_H_
#define EMNAPI_INCLUDE_EMNAPI_H_

#include <stdbool.h>
#include "js_native_api_types.h"
#include "emnapi_common.h"

#define EMNAPI_MAJOR_VERSION 1
#define EMNAPI_MINOR_VERSION 11
#define EMNAPI_PATCH_VERSION 2

typedef enum {
  emnapi_runtime,
  emnapi_userland,
} emnapi_ownership;

typedef enum {
  emnapi_int8_array,
  emnapi_uint8_array,
  emnapi_uint8_clamped_array,
  emnapi_int16_array,
  emnapi_uint16_array,
  emnapi_int32_array,
  emnapi_uint32_array,
  emnapi_float32_array,
  emnapi_float64_array,
  emnapi_bigint64_array,
  emnapi_biguint64_array,
  emnapi_float16_array,
  emnapi_data_view = -1,
  emnapi_buffer = -2,
} emnapi_memory_view_type;

EXTERN_C_START

EMNAPI_EXTERN int emnapi_is_support_weakref();
EMNAPI_EXTERN int emnapi_is_support_bigint();
EMNAPI_EXTERN int emnapi_is_node_binding_available();

#ifdef __EMSCRIPTEN__
EMNAPI_EXTERN
napi_status emnapi_get_module_object(napi_env env,
                                     napi_value* result);

EMNAPI_EXTERN
napi_status emnapi_get_module_property(napi_env env,
                                       const char* utf8name,
                                       napi_value* result);
#endif

typedef struct {
  uint32_t major;
  uint32_t minor;
  uint32_t patch;
} emnapi_runtime_version;

EMNAPI_EXTERN
napi_status emnapi_get_runtime_version(napi_env env, 
                                       emnapi_runtime_version* version);

EMNAPI_EXTERN
napi_status emnapi_create_memory_view(napi_env env,
                                      emnapi_memory_view_type type,
                                      void* external_data,
                                      size_t byte_length,
                                      napi_finalize finalize_cb,
                                      void* finalize_hint,
                                      napi_value* result);


EMNAPI_EXTERN
napi_status emnapi_sync_memory(napi_env env,
                               bool js_to_wasm,
                               napi_value* arraybuffer_or_view,
                               size_t byte_offset,
                               size_t length);

EMNAPI_EXTERN
napi_status emnapi_get_memory_address(napi_env env,
                                      napi_value arraybuffer_or_view,
                                      void** address,
                                      emnapi_ownership* ownership,
                                      bool* runtime_allocated);

/**
 * Get the handle for an external SharedArrayBuffer.
 * This function must be called on the emnapi main thread.
 */
EMNAPI_EXTERN
napi_status emnapi_get_external_sharedarraybuffer_handle(
    napi_env env,
    napi_value sharedarraybuffer,
    void** handle);

/**
 * Acquire a reference to an external SharedArrayBuffer handle.
 * This function may be called from any thread.
 */
EMNAPI_EXTERN
void emnapi_acquire_external_sharedarraybuffer(void* handle);

/**
 * Release a reference to an external SharedArrayBuffer handle.
 * When the refcount reaches zero, finalize_cb is invoked.
 * This function may be called from any thread.
 */
EMNAPI_EXTERN
void emnapi_release_external_sharedarraybuffer(void* handle);

EXTERN_C_END

#endif
