/*
 * Copyright (c) 2021-2026 Huawei Device Co., Ltd.
 * 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 FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H
#define FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H

#include <cstdint>
#include <functional>
#include <list>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#ifdef LINUX_PLATFORM
#include<atomic>
#endif

#include "callback_scope_manager/native_callback_scope_manager.h"
#include "ecmascript/napi/include/jsnapi.h"
#include "interfaces/inner_api/napi/native_node_hybrid_api.h"
#include "module_manager/native_module_manager.h"
#include "native_engine/native_async_work.h"
#include "native_engine/native_deferred.h"
#include "native_engine/native_reference.h"
#include "native_engine/native_safe_async_work.h"
#include "native_engine/native_event.h"
#include "native_engine/native_value.h"
#include "native_property.h"
#include "reference_manager/native_reference_manager.h"
#include "utils/macros.h"
#include "utils/data_protector.h"

namespace panda::ecmascript {
    class EcmaVM;
}

typedef int32_t (*GetContainerScopeIdCallback)(void);
typedef void (*ContainerScopeCallback)(int32_t);
typedef struct uv_loop_s uv_loop_t;

struct NativeErrorExtendedInfo {
    const char* message = nullptr;
    void* reserved = nullptr;
    uint32_t engineErrorCode = 0;
    int errorCode = 0;
};

enum LoopMode {
    LOOP_DEFAULT, LOOP_ONCE, LOOP_NOWAIT
};

enum class DumpFormat {
    JSON, BINARY, OTHER
};

enum class WorkerVersion {
    NONE, OLD, NEW
};

class WorkerThreadState {
public:
    uint32_t CheckIdleState()
    {
        if (!isRunning_.load() && taskCount_ <= (lastTaskCount_ + IDLE_CHECK_COUNT)) {
            lastTaskCount_ = taskCount_;
            return ++checkCount_;
        }
        checkCount_ = 0;
        lastTaskCount_ = taskCount_;
        return checkCount_;
    }

    uint32_t GetCheckCount()
    {
        return checkCount_;
    }

    void ResetCheckCount()
    {
        checkCount_ = 0;
    }

    void NoityTaskStart()
    {
        taskCount_++;
        isRunning_.store(true);
    }

    void NotifyTaskEnd()
    {
        isRunning_.store(false);
    }
private:
    static constexpr uint32_t IDLE_CHECK_COUNT = 5;
    std::atomic<bool> isRunning_ {false};
    uint32_t taskCount_ {0};
    uint32_t lastTaskCount_ {0};
    uint32_t checkCount_ {0};
};

using CleanupCallback = void (*)(void*);
using CleanupFinalizerCallBack = void (*)(void*);
using ThreadId = uint32_t;
class NapiOptions;
using PostTask = std::function<void(bool needSync)>;
using CleanEnv = std::function<void()>;
using InitWorkerFunc = std::function<void(NativeEngine* engine)>;
using GetAssetFunc = std::function<void(const std::string& uri, uint8_t **buff, size_t *buffSize,
    std::vector<uint8_t>& content, std::string& ami, bool &useSecureMem, void** mapper, bool isRestricted)>;
using OffWorkerFunc = std::function<void(NativeEngine* engine)>;
using ReleaseWorkerSafeMemFunc = std::function<void(void* fileMapper)>;
using DebuggerPostTask = std::function<void(std::function<void()>&&)>;
using NapiUncaughtExceptionCallback = std::function<void(napi_value value)>;
using PermissionCheckCallback = std::function<bool()>;
using NapiConcurrentCallback = void (*)(napi_env env, napi_value result, bool success, void* data);
using SourceMapCallback = std::function<std::string(const std::string& rawStack)>;
using SourceMapTranslateCallback = std::function<bool(std::string& url, int& line, int& column,
    std::string& packageName)>;
using AppFreezeFilterCallback = std::function<bool(const int32_t pid, const bool needDecreaseQuota,
    std::string &eventConfig)>;
using EcmaVM = panda::ecmascript::EcmaVM;
using JsFrameInfo = panda::ecmascript::JsFrameInfo;
using HeapMemoryInfo = panda::ecmascript::HeapMemoryInfo;
using NapiOnWorkerErrorCallback = std::function<bool(napi_env env,
    napi_value exception, std::string name, uint32_t type)>;
using NapiOnMainThreadErrorCallback = std::function<bool(napi_env env,
    std::string summary, std::string name, std::string message, std::string stack)>;
using NapiAllUnhandledRejectionCallback = std::function<bool(napi_env env,
    napi_value* args, std::string name, uint32_t type)>;
using NapiAllPromiseRejectCallback = std::function<void(napi_value* args)>;
using NapiHasOnErrorCallback = std::function<bool()>;
using NapiHasAllUnhandledRejectionCallback = std::function<bool()>;
using GCTaskFinishedCallback = std::function<void()>;
using SerializeOptions = panda::SerializeOptions;
using TaskPoolShrinkCallback = std::function<void(bool inBackground)>;

// Define method to load counter values of different types
#define NAPI_COUNTER_ATOMIC_LOAD(storage) (storage).load()
#define NAPI_COUNTER_INT32_LOAD(storage) (storage)

// Counter macro template: used to uniformly declare and process multiple counters.
// Usage: pass a macro XX(type, name, storage, LOAD_MACRO), which will be applied to each counter entry.
#define NAPI_COUNTER_METHOD(XX)                                                     \
    /* Thread-safe counters (using std::atomic<int>) */                             \
    /* Note: async_work queue operations are NOT thread-safe, */                    \
    /* but these counters themselves are atomic */                                  \
    XX(std::atomic<int>, WaitingRequest, requestWaiting_, NAPI_COUNTER_ATOMIC_LOAD) \
    XX(std::atomic<int>, Listening, listeningCounter_, NAPI_COUNTER_ATOMIC_LOAD)    \
    /* Sub Native Engine related counters */                                        \
    XX(std::atomic<int>, SubEnv, subEnvCounter_, NAPI_COUNTER_ATOMIC_LOAD)          \
                                                                                    \
    /* Non-thread-safe counters (must access/modify in the env-running thread) */   \
    /* Thread-Safe Function (TSFN): creation is not thread-safe, */                 \
    /* release will be done via uv_async */                                         \
    XX(int32_t, ActiveTsfn, activeTsfnCounter_, NAPI_COUNTER_INT32_LOAD)            \
    /* Count of Sub Context Engine instances */                                     \
    XX(int32_t, SubContextEnv, subContextEnvCounter_, NAPI_COUNTER_INT32_LOAD)      \
    XX(int64_t, CallbackbleRef, callbackbleRefCounter_, NAPI_COUNTER_INT32_LOAD)    \
    XX(int64_t, NonCallbackRef, nonCallbackRefCounter_, NAPI_COUNTER_INT32_LOAD)    \
    XX(int64_t, RuntimeOwnedRef, runtimeOwnedRefCounter_, NAPI_COUNTER_INT32_LOAD)

// Heap memory threshold configuration
struct HeapMemoryThreshold {
    double localHeapThreshold;
    double sharedHeapThreshold;
    double processHeapThreshold;
};

class NAPI_EXPORT NativeEngine {
public:
    explicit NativeEngine(void* jsEngine);
    explicit NativeEngine(NativeEngine* parent);
    virtual ~NativeEngine();

    virtual NativeModuleManager* GetModuleManager();
    virtual NativeReferenceManager* GetReferenceManager();
    virtual NativeCallbackScopeManager* GetCallbackScopeManager();
    virtual uv_loop_t* GetUVLoop() const;
    virtual pthread_t GetTid() const;
    inline ThreadId GetSysTid() const
    {
        return sysTid_;
    };
    static ThreadId GetCurSysTid();
    inline uint64_t GetId() const
    {
        return id_;
    };

    virtual bool ReinitUVLoop();

    virtual void Loop(LoopMode mode, bool needSync = false);
    virtual void SetPostTask(PostTask postTask);
    virtual void TriggerPostTask();
#if !defined(PREVIEW)
    virtual void CheckUVLoop();
    virtual void CancelCheckUVLoop();
#endif
    virtual void* GetJsEngine();

    virtual const EcmaVM* GetEcmaVm() const = 0;
    virtual const EcmaVM* GetEcmaVmCritical() const = 0;
    virtual const NativeEngine* GetParent() const = 0;
    
    virtual bool NapiNewTypedArray(NativeTypedArrayType typedArrayType,
                                   panda::Local<panda::ArrayBufferRef> arrayBuf, size_t byte_offset,
                                   size_t length, napi_value* result) = 0;
    virtual bool NapiNewSendableTypedArray(NativeTypedArrayType typedArrayType,
                                           panda::Local<panda::SendableArrayBufferRef> arrayBuf, size_t byte_offset,
                                           size_t length, napi_value* result) = 0;
    virtual NativeTypedArrayType GetTypedArrayType(panda::Local<panda::TypedArrayRef> typedArray) = 0;
    virtual NativeTypedArrayType GetSendableTypedArrayType(panda::Local<panda::SendableTypedArrayRef> typedArray) = 0;
    virtual void SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef) = 0;

    virtual bool InitTaskPoolThread(NativeEngine* engine, NapiConcurrentCallback callback) = 0;
    virtual bool InitTaskPoolThread(napi_env env, NapiConcurrentCallback callback) = 0;
    virtual bool InitTaskPoolFunc(napi_env env, napi_value func, void* taskInfo) = 0;
    virtual void ClearCurrentTaskInfo() = 0;
    virtual bool HasPendingJob() const = 0;
    virtual bool IsProfiling() const = 0;
    virtual bool IsExecutingPendingJob() const = 0;
    virtual void* GetCurrentTaskInfo() const = 0;
    virtual void TerminateExecution() const = 0;
    virtual void NotifyTaskBegin() const = 0;
    virtual void NotifyTaskFinished() const = 0;

    virtual napi_value CallFunction(napi_value thisVar,
                                    napi_value function,
                                    napi_value const *argv,
                                    size_t argc) = 0;
    virtual bool RunScriptPath(const char* path, bool checkPath = false) = 0;
    virtual napi_value RunScriptBuffer(const char* path, std::vector<uint8_t>& buffer, bool isBundle,
        bool needUpdate = false) = 0;
    virtual bool RunScriptBuffer(const std::string &path, uint8_t* buffer, size_t size, bool isBundle) = 0;
    virtual napi_value RunBufferScript(std::vector<uint8_t>& buffer) = 0;
    virtual napi_value RunActor(uint8_t* buffer, size_t bufferSize,
        const char* descriptor, char* entryPoint = nullptr, bool checkPath = false, void* fileMapper = nullptr) = 0;

    virtual napi_value CreateInstance(napi_value constructor, napi_value const *argv, size_t argc) = 0;

    virtual NativeReference* CreateReference(napi_value value, uint32_t initialRefcount,
        bool flag = false, NapiNativeFinalize callback = nullptr, void* data = nullptr, void* hint = nullptr,
        size_t nativeBindingSize = 0) = 0;

    virtual NativeReference* CreateAsyncReference(napi_value value, uint32_t initialRefcount,
        bool flag = false, NapiNativeFinalize callback = nullptr, void* data = nullptr, void* hint = nullptr) = 0;

    virtual NativeAsyncWork* CreateAsyncWork(napi_value asyncResource,
                                             napi_value asyncResourceName,
                                             NativeAsyncExecuteCallback execute,
                                             NativeAsyncCompleteCallback complete,
                                             void* data);

    virtual NativeAsyncWork* CreateAsyncWork(const std::string &asyncResourceName,
                                             NativeAsyncExecuteCallback execute,
                                             NativeAsyncCompleteCallback complete,
                                             void* data);
    virtual NativeSafeAsyncWork* CreateSafeAsyncWork(napi_value func, napi_value asyncResource,
        napi_value asyncResourceName, size_t maxQueueSize, size_t threadCount, void* finalizeData,
        NativeFinalize finalizeCallback, void* context, NativeThreadSafeFunctionCallJs callJsCallback);
    virtual void* CreateRuntime(bool isLimitedWorker = false) = 0;
    virtual napi_value CreatePromise(NativeDeferred** deferred) = 0;

    virtual void SetJsDumpThresholds(size_t thresholds) = 0;
    virtual void SetAppFreezeFilterCallback(AppFreezeFilterCallback callback) = 0;
    virtual void SetRawHeapTrimLevel(uint32_t level) = 0;
    virtual void SetProcDumpInSharedOOM(bool enable) = 0;

    virtual void StartCpuProfiler(const std::string& fileName = "") = 0;
    virtual void StopCpuProfiler() = 0;

    virtual void ResumeVM() = 0;
    virtual bool SuspendVM() = 0;
    virtual bool IsSuspended() = 0;
    virtual bool CheckSafepoint() = 0;
    virtual bool SuspendVMById(uint32_t tid) = 0;
    virtual void ResumeVMById(uint32_t tid) = 0;

    virtual void DumpHeapSnapshot(const std::string &path, bool isVmMode = true,
        DumpFormat dumpFormat = DumpFormat::JSON, bool isPrivate = false,
        bool captureNumericValue = false, bool isJSLeakWatcher = false,
        bool isClearNodeIdCache = false) = 0;
    virtual void DumpHeapSnapshot(bool isFullGC, const std::string &path,
        const std::function<void(uint8_t)> &callback, bool isClearNodeIdCache = false, bool isProcDump = false) = 0;
    virtual void DumpCpuProfile() = 0;
    virtual void DumpHeapSnapshot(bool isVmMode = true, DumpFormat dumpFormat = DumpFormat::JSON,
        bool isPrivate = false, bool isFullGC = true, bool isClearNodeIdCache = false) = 0;
    virtual bool BuildNativeAndJsStackTrace(std::string &stackTraceStr) = 0;
    virtual bool BuildJsStackTrace(std::string &stackTraceStr) = 0;
    virtual bool BuildJsStackInfoListWithCustomDepth(std::vector<JsFrameInfo>& jsFrames)
        = 0;
    virtual void GetMainThreadStackTrace(napi_env env, std::string &stackTraceStr) = 0;
    virtual bool OnVMHeapMemoryPressure(napi_env env, HeapMemoryThreshold heapMemoryThreshold,
                                        napi_value callback) = 0;
    virtual void OffVMHeapMemoryPressure(napi_env env) = 0;
    virtual void SetMultithreadingDetectionEnabled(napi_env env, bool enabled, bool abort,
                                                   int64_t frequency, int64_t interval) = 0;
    virtual bool GetDetectionAbort() = 0;
    virtual int64_t GetDetectionFrequency() = 0;
    virtual int64_t GetDetectionInterval() = 0;
    virtual std::vector<HeapMemoryInfo> GetAllVMHeapMemoryInfo() = 0;
    virtual bool EnableLocalHandleDetection() = 0;
    virtual void GetHybridStackTraceForCrash(napi_env env, std::string &stackTraceStr) = 0;
    virtual void GetJsonExtraInfoForCrash(napi_env env, std::string &jsonStr, uint32_t &position) = 0;
    virtual void SerializeJSError(napi_env env, napi_value object,
                                  const SerializeOptions& options, void** result) = 0;
    virtual void SerializeJSErrorWithError(napi_env env, napi_value object,
                                           const SerializeOptions& options, void** result,
                                           std::string& error) = 0;
    virtual bool DeleteWorker(NativeEngine* workerEngine) = 0;
    virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true) = 0;
    virtual bool StopHeapTracking(const std::string &filePath) = 0;

    virtual void AllowCrossThreadExecution() const = 0;
    virtual void SetThreadName(const std::string &name) = 0;

    NativeErrorExtendedInfo* GetLastError();
    void SetLastError(int errorCode, uint32_t engineErrorCode = 0, void* engineReserved = nullptr);
    void ClearLastError()
    {
        lastError_.errorCode = 0;
        lastError_.engineErrorCode = 0;
        lastError_.message = nullptr;
        lastError_.reserved = nullptr;
    }
    void EncodeToUtf8(napi_value value, char* buffer, uint32_t* written, size_t bufferSize, int32_t* nchars);
    void EncodeToChinese(napi_value value, std::string& buffer, const std::string& encoding);
    NativeEngine(NativeEngine&) = delete;
    virtual NativeEngine& operator=(NativeEngine&) = delete;

    virtual napi_value ValueToNapiValue(JSValueWrapper& value) = 0;
    virtual std::string GetSourceCodeInfo(napi_value value, ErrorPos pos) = 0;

    virtual void TriggerFatalException(panda::Local<panda::JSValueRef> exceptionValue) = 0;
    virtual bool AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue) = 0;

#define NATIVE_ENGINE_THREAD_TYPE(XX)                   \
    XX(MainThread, MAIN_THREAD)                         \
    XX(WorkerThread, WORKER_THREAD)                     \
    XX(RestrictedWorkerThread, RESTRICTEDWORKER_THREAD) \
    XX(TaskPoolThread, TASKPOOL_THREAD)                 \
    XX(FormThread, FORM_THREAD)                         \
    XX(NativeThread, NATIVE_THREAD)

#define GEN_THREAD_TYPE_METHOD(name, type)                                               \
    void Mark##name()                                                                    \
    {                                                                                    \
        jsThreadType_.Update(static_cast<uintptr_t>(JSThreadType::type));                \
    }                                                                                    \
    bool Is##name() const                                                                \
    {                                                                                    \
        return static_cast<JSThreadType>(jsThreadType_.GetData()) == JSThreadType::type; \
    }

    NATIVE_ENGINE_THREAD_TYPE(GEN_THREAD_TYPE_METHOD)

#undef GEN_THREAD_TYPE_METHOD

private:
    // the old worker api use before api9, the new worker api start with api9
#define GEN_THREAD_TYPE_ENUM(_, type) type,
    enum JSThreadType { NATIVE_ENGINE_THREAD_TYPE(GEN_THREAD_TYPE_ENUM) };
#undef GEN_THREAD_TYPE_ENUM

#undef NATIVE_ENGINE_THREAD_TYPE

    DataProtector jsThreadType_ {DataProtector(uintptr_t(JSThreadType::MAIN_THREAD))};

public:
    bool CheckAndSetWorkerVersion(WorkerVersion expected, WorkerVersion desired)
    {
        return workerVersion_.compare_exchange_strong(expected, desired);
    }
    bool IsTargetWorkerVersion(WorkerVersion target) const
    {
        return workerVersion_.load() == target;
    }

#define DCL_COUNTER_METHOD(_type, name, _storage, _LOAD) \
    void Increase##name##Counter();                      \
    void Decrease##name##Counter();                      \
    bool Has##name() const;
    NAPI_COUNTER_METHOD(DCL_COUNTER_METHOD)
#undef DCL_COUNTER_METHOD

    void IncreaseCriticalScopeCounter();
    void DecreaseCriticalScopeCounter();
    bool HasCriticalScope() const;

    // alias for HasListening
    bool HasListeningCounter();
    void SetCleanEnv(CleanEnv cleanEnv)
    {
        cleanEnv_ = cleanEnv;
    }

    // register init worker func
    virtual void SetInitWorkerFunc(InitWorkerFunc func);
    InitWorkerFunc GetInitWorkerFunc() const;
    virtual void SetGetAssetFunc(GetAssetFunc func);
    GetAssetFunc GetGetAssetFunc() const;
    virtual void SetOffWorkerFunc(OffWorkerFunc func);
    OffWorkerFunc GetOffWorkerFunc() const;
    virtual void SetReleaseWorkerSafeMemFunc(ReleaseWorkerSafeMemFunc func);
    ReleaseWorkerSafeMemFunc GetReleaseWorkerSafeMemFunc() const;

    virtual void SetExternalClearCallback(std::function<void()>&& func) = 0;
    // call init worker func
    virtual bool CallInitWorkerFunc(NativeEngine* engine);
    virtual bool CallGetAssetFunc(const std::string& uri, uint8_t **buff, size_t *buffSize,
        std::vector<uint8_t>& content, std::string& ami, bool &useSecureMem, void** mapper, bool isRestricted);
    virtual bool CallOffWorkerFunc(NativeEngine* engine);

    // adapt worker to ace container
    virtual void SetGetContainerScopeIdFunc(GetContainerScopeIdCallback func);
    virtual void SetInitContainerScopeFunc(ContainerScopeCallback func);
    virtual void SetFinishContainerScopeFunc(ContainerScopeCallback func);
    virtual int32_t GetContainerScopeIdFunc();
    virtual bool InitContainerScopeFunc(int32_t id);
    virtual bool FinishContainerScopeFunc(int32_t id);

#if !defined(PREVIEW)
    virtual void SetDebuggerPostTaskFunc(DebuggerPostTask func);
    virtual void CallDebuggerPostTaskFunc(std::function<void()>&& task);
#endif

    virtual void SetHostEngine(NativeEngine* engine);
    virtual NativeEngine* GetHostEngine() const;
    virtual void SetApiVersion(int32_t apiVersion);
    virtual int32_t GetApiVersion();
    virtual int32_t GetRealApiVersion();
    virtual bool IsApplicationApiVersionAPI11Plus();

    virtual napi_status AddCleanupHook(CleanupCallback fun, void* arg);
    virtual napi_status RemoveCleanupHook(CleanupCallback fun, void* arg);
    virtual napi_status AddCleanupFinalizer(CleanupFinalizerCallBack fun, void* arg);
    virtual napi_status RemoveCleanupFinalizer(CleanupFinalizerCallBack fun, void* arg);
    void RunCleanupHooks(bool waitTasks);

    void CleanupHandles();

    inline static bool IsAlive(NativeEngine* env)
    {
        std::lock_guard<std::mutex> alivedEngLock(g_alivedEngineMutex_);
        return g_alivedEngine_.find(env) != g_alivedEngine_.end();
    }

    virtual void RunCleanup();

    bool IsStopping() const
    {
        return isStopping_.load();
    }

    void SetStopping(bool value)
    {
        isStopping_.store(value);
    }

    virtual void PrintStatisticResult() = 0;
    virtual void StartRuntimeStat() = 0;
    virtual void StopRuntimeStat() = 0;
    virtual size_t GetArrayBufferSize() = 0;
    virtual size_t GetHeapTotalSize() = 0;
    virtual size_t GetHeapUsedSize() = 0;
    virtual size_t GetHeapObjectSize() = 0;
    virtual size_t GetHeapLimitSize() = 0;
    virtual size_t GetProcessHeapLimitSize() = 0;
    virtual size_t GetGCCount() = 0;
    virtual size_t GetGCDuration() = 0;
    virtual size_t GetAccumulatedAllocateSize() = 0;
    virtual size_t GetAccumulatedFreeSize() = 0;
    virtual size_t GetFullGCLongTimeCount() = 0;
    virtual void NotifyApplicationState(bool inBackground) = 0;
    virtual void NotifyIdleStatusControl(std::function<void(bool)> callback) = 0;
    virtual void NotifyIdleTime(int idleMicroSec) = 0;
    virtual void NotifyMemoryPressure(bool inHighMemoryPressure = false) = 0;
    virtual void NotifyForceExpandState(int32_t value) = 0;
    virtual void NotifyForceExpandState(uint64_t tid, int32_t value) = 0;
    virtual void RegisterAppStateCallback(NapiAppStateCallback callback) = 0;
    virtual void SetMockModuleList(const std::map<std::string, std::string> &list) = 0;
    virtual int32_t GetObjectHash(napi_env env, napi_value src) = 0;

    void RegisterWorkerFunction(const NativeEngine* engine);
    virtual void RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback callback) = 0;
    virtual void RegisterAllPromiseCallback(NapiAllPromiseRejectCallback callback) = 0;
    virtual void HandleUncaughtException() = 0;
    virtual bool HasPendingException()
    {
        return false;
    }
    virtual void ThrowException(const char* msg);
    virtual void RegisterPermissionCheck(PermissionCheckCallback callback) = 0;
    virtual bool ExecutePermissionCheck() = 0;
    virtual void RegisterTranslateBySourceMap(SourceMapCallback callback) = 0;
    virtual std::string ExecuteTranslateBySourceMap(const std::string& rawStack) = 0;
    virtual void RegisterSourceMapTranslateCallback(SourceMapTranslateCallback callback) = 0;
    virtual void SetPromiseRejectCallBackRef(NativeReference*) = 0;
    virtual void SetCheckCallbackRef(NativeReference*) = 0;
    virtual NapiUncaughtExceptionCallback GetNapiUncaughtExceptionCallback() = 0;
    virtual void* GetPromiseRejectCallback() = 0;
    virtual void GetCurrentModuleInfo(std::string& moduleName, std::string& fileName, bool needRecordName) = 0;
    virtual bool GetIsBundle() = 0;
    virtual bool GetIsNormalizedOhmUrlPack() = 0;
    virtual bool GetIsDebugModeEnabled() = 0;
    virtual std::string GetBundleName() = 0;
    virtual bool IsExecuteModuleInAbcFile(std::string bundleName, std::string moduleName, std::string ohmurl) = 0;
    virtual int GetProcessStartRealTime() = 0;
    virtual void PostTriggerGCTask(panda::TriggerGCData& data, GCTaskFinishedCallback callback = nullptr) = 0;
    // run script by path
    napi_value RunScriptForAbc(const char* path, char* entryPoint = nullptr);
    napi_value RunScript(const char* path, char* entryPoint = nullptr);
    napi_value RunScriptInRestrictedThread(const char* path);
    napi_value GetAbcBufferAndRunActor(std::string pathStr, char* entryPoint);
    bool GetAbcBuffer(const char* path, uint8_t **buffer, size_t* bufferSize, std::vector<uint8_t>& content,
        std::string& ami, void** mapper, bool isRestrictedWorker = false);

    const char* GetModuleFileName();

    void SetModuleName(std::string &moduleName);
    void SetModuleFileName(std::string &moduleFileName);

    void SetInstanceData(void* data, NativeFinalize finalize_cb, void* hint);
    void GetInstanceData(void** data);

    /**
     * @brief Set the Extension Infos
     *
     * @param extensionInfos extension infos to set
     */
    void SetExtensionInfos(std::unordered_map<std::string, int32_t>&& extensionInfos);

    /**
     * @brief Get the Extension Infos
     *
     * @return extension infos
     */
    const std::unordered_map<std::string, int32_t>& GetExtensionInfos();

    /**
     * @brief Set the Module Blocklist
     *
     * @param blocklist the blocklist set to native engine
     */
    void SetModuleBlocklist(std::unordered_map<int32_t, std::unordered_set<std::string>>&& blocklist);

    /**
     * @brief Set the Module Load Checker
     *
     * @param moduleCheckerDelegate the module checker delegate will intercept the module loading
     */
    void SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate>& moduleCheckerDelegate);

    virtual napi_value NapiLoadModule(const char* path) = 0;
    virtual napi_value NapiLoadModuleWithInfo(const char* path, const char* module_info) = 0;
    virtual napi_value NapiLoadModuleWithInfoForHybridApp(const char* path, const char* module_info,
                                                          const char* ohmurl, const char* abcFilePath) = 0;
    virtual std::string GetPkgName(const std::string &moduleName) = 0;

    double NewAsyncId()
    {
        return 0;
    }

    double GetDefaultTriggerAsyncId()
    {
        return 0;
    }

    /**
     * @brief run the uv loop in the engine by the designated uv run mode
     *
     * @param mode the specified uv mode that utilized to tell uv which mode will be used to run the uv loop
     */
    napi_status RunEventLoop(napi_event_mode mode);

    /**
     * @brief stop the uv loop in the engine
     */
    napi_status StopEventLoop();

    virtual bool IsCrossThreadCheckEnabled() const
    {
        return crossThreadCheck_;
    }
    virtual void UpdateCrossThreadCheckStatus()
    {
        crossThreadCheck_ = panda::JSNApi::IsMultiThreadCheckEnabled(GetEcmaVm());
    }
    virtual bool IsContainerScopeEnabled() const = 0;

    bool IsInDestructor() const
    {
        return isInDestructor_;
    }

    static NativeEngine* GetMainThreadEngine()
    {
        std::lock_guard<std::mutex> lock(g_mainThreadEngineMutex_);
        return g_mainThreadEngine_;
    }

    static void SetMainThreadEngine(NativeEngine* engine)
    {
        if (g_mainThreadEngine_ == nullptr) {
            std::lock_guard<std::mutex> lock(g_mainThreadEngineMutex_);
            if (g_mainThreadEngine_ == nullptr) {
                g_mainThreadEngine_ = engine;
            }
        }
    }

    void HandleTaskpoolException(napi_value exception)
    {
        auto callback = this->GetNapiUncaughtExceptionCallback();
        if (callback) {
            callback(exception);
        }
    }

    WorkerThreadState* GetWorkerThreadState()
    {
        return workerThreadState_;
    }

    virtual bool IsMainEnvContext() const = 0;

    virtual bool IsMultiContextEnabled() const = 0;

    virtual void SetMultiContextEnabled(bool enabled) = 0;

    virtual panda::Local<panda::JSValueRef> GetContext() const = 0;

    virtual napi_status SwitchContext() = 0;

    virtual napi_status DestroyContext() = 0;

    virtual void NotifyVMIgnoreFinalizeCallback() const = 0;

    virtual void SetTaskpoolShrinkCallback(TaskPoolShrinkCallback callback) = 0;

    inline void SetInstanceId(int32_t id) {
        instanceId_ = id;
    };

    inline int32_t GetInstanceId() {
        return instanceId_;
    };

    template <typename T, typename... Args>
    static inline void ExecuteCallback(const std::string& func, T&& call, Args... args) {
        panda::ArkCrashHolder holder("NAPI", func);
        holder.UpdateCallbackPtr(reinterpret_cast<uintptr_t>(call));
        call(args...);
    }

private:
    void InitUvField();

    virtual NapiOptions *GetNapiOptions() const = 0;

    virtual void EnableNapiProfiler() = 0;

protected:
    virtual bool IsLimitWorker() const = 0;
    uint64_t GetNonCallbackRefCount();
    uint64_t GetCallbackbleRefCount();

    void *jsEngine_ = nullptr;

    void Init();
    void Deinit();
    // For context env
    void InitWithoutUV();
    void DeinitWithoutUV();

    inline void SetDead()
    {
        std::lock_guard<std::mutex> alivedEngLock(g_alivedEngineMutex_);
        g_alivedEngine_.erase(this);
        return;
    }

    // should only call once in life cycle of ArkNativeEngine(NativeEngine)
    inline void SetAlive();

    virtual void RunInstanceFinalizer();

    NativeModuleManager* moduleManager_ = nullptr;
    NativeReferenceManager* referenceManager_ = nullptr;
    NativeCallbackScopeManager* callbackScopeManager_ = nullptr;

    uv_loop_t* loop_ = nullptr;

    NativeErrorExtendedInfo lastError_;

    // register for worker
    void* worker_ = nullptr;
    InitWorkerFunc initWorkerFunc_ {nullptr};
    GetAssetFunc getAssetFunc_ {nullptr};
    OffWorkerFunc offWorkerFunc_ {nullptr};
#if !defined(PREVIEW)
    DebuggerPostTask debuggerPostTaskFunc_ {nullptr};
#endif
    NativeEngine* hostEngine_ {nullptr};
    bool isAppModule_ = false;
    WorkerThreadState* workerThreadState_;
    static std::unordered_set<NativeEngine*> g_alivedEngine_;
public:
    uint64_t openHandleScopes_ = 0;
    panda::Local<panda::ObjectRef> lastException_;

private:
    std::string moduleName_;
    std::string moduleFileName_;
    std::mutex instanceDataLock_;
    bool crossThreadCheck_ = false;
    NativeObjectInfo instanceDataInfo_;
    void FinalizerInstanceData(void);
    pthread_t tid_ { 0 };
    ThreadId sysTid_ { 0 };
    uint64_t id_ { 0 };
    std::unordered_map<std::string, int32_t> extensionInfos_;
    uv_sem_t uvSem_;
    // Application's sdk version
    int32_t apiVersion_ = 8;
    int32_t realApiVersion_ = 8;

    // current is hostengine, can create old worker, new worker, or no workers on hostengine
    std::atomic<WorkerVersion> workerVersion_ { WorkerVersion::NONE };
#if !defined(PREVIEW)
    static void UVThreadRunner(void* nativeEngine);
    void PostLoopTask();

    bool checkUVLoop_ = false;
    uv_thread_t uvThread_;
#endif
    mutable std::shared_mutex eventMutex_;
    napi_threadsafe_function defaultFunc_ = nullptr;
    // Record the instance of FA model to find the correct ArkUI instance while posting cross-thread task
    int32_t instanceId_ = -1;
    PostTask postTask_ = nullptr;
    CleanEnv cleanEnv_ = nullptr;
    uv_async_t uvAsync_;
    std::unordered_map<void*, std::pair<CleanupCallback, uint64_t>> cleanupHooks_;
    uint64_t cleanupHookCounter_ = 0;
    std::unordered_map<void*, std::pair<CleanupFinalizerCallBack, uint64_t>> instanceFinalizer_;
    uint64_t instanceFinalizerCounter_ = 0;

#define DCL_STORAGE_COUNTER(type, _name, storage, _LOAD) type (storage) { 0 };
    NAPI_COUNTER_METHOD(DCL_STORAGE_COUNTER)
#undef DCL_STORAGE_COUNTER
    std::shared_ptr<uint64_t> criticalScopeCounter_ {};

    std::atomic_bool isStopping_ { false };

    std::mutex loopRunningMutex_;
    bool isLoopRunning_ = false;
    bool isInDestructor_ {false};
    std::string taskName_ = "";

    // protect alived engine set and last engine id
    static std::mutex g_alivedEngineMutex_;
    static uint64_t g_lastEngineId_;
    static std::mutex g_mainThreadEngineMutex_;
    static NativeEngine* g_mainThreadEngine_;

public:
    inline std::shared_mutex& GetEventMutex() const
    {
        return eventMutex_;
    }

    inline napi_threadsafe_function GetDefaultFunc()
    {
        return defaultFunc_;
    }

    inline static bool IsAliveLocked(NativeEngine* env)
    {
        return g_alivedEngine_.find(env) != g_alivedEngine_.end();
    }

    inline static std::mutex& GetAliveEngineMutex() {
        return g_alivedEngineMutex_;
    }
};

class NapiErrorManager {
public:
    static NapiErrorManager* GetInstance();

    void RegisterOnErrorCallback(NapiOnWorkerErrorCallback workerErrorCb,
        NapiOnMainThreadErrorCallback mainThreadErrorCb)
    {
        if (!onWorkerErrorCb_) {
            onWorkerErrorCb_ = workerErrorCb;
        }
        if (!onMainThreadErrorCb_) {
            onMainThreadErrorCb_ = mainThreadErrorCb;
        }
    }

    NapiOnWorkerErrorCallback &GetOnWorkerErrorCallback()
    {
        return onWorkerErrorCb_;
    }

    NapiOnMainThreadErrorCallback &GetOnMainThreadErrorCallback()
    {
        return onMainThreadErrorCb_;
    }

    void RegisterAllUnhandledRejectionCallback(NapiAllUnhandledRejectionCallback callback)
    {
        if (!allUnhandledRejectionCb_) {
            allUnhandledRejectionCb_ = callback;
        }
    }

    NapiAllUnhandledRejectionCallback &GetAllUnhandledRejectionCallback()
    {
        return allUnhandledRejectionCb_;
    }

    void RegisterGlobalUnhandledRejectionCheckCallback(napi_callback callback)
    {
        if (!globalUnhandledRejectionCheckCb_) {
            globalUnhandledRejectionCheckCb_ = callback;
        }
    }

    napi_callback &GetGlobalUnhandledRejectionCheckCallback()
    {
        return globalUnhandledRejectionCheckCb_;
    }

    void RegisterHasOnErrorCallback(NapiHasOnErrorCallback callback)
    {
        if (!hasOnErrorCb_) {
            hasOnErrorCb_ = callback;
        }
    }

    NapiHasOnErrorCallback &GetHasErrorCallback()
    {
        return hasOnErrorCb_;
    }

    void RegisterHasAllUnhandledRejectionCallback(NapiHasAllUnhandledRejectionCallback callback)
    {
        if (!hasAllUnhandledRejectionCb_) {
            hasAllUnhandledRejectionCb_ = callback;
        }
    }

    NapiHasAllUnhandledRejectionCallback &GetHasAllUnhandledRejectionCallback()
    {
        return hasAllUnhandledRejectionCb_;
    }

    void NotifyUncaughtException(napi_env env, napi_value exception, std::string name, uint32_t type);
    bool NotifyUncaughtException(napi_env env, const std::string &summary, const std::string &name,
        const std::string &message, const std::string &stack);
    void NotifyUnhandledRejection(napi_env env, napi_value* exception, std::string name, uint32_t type);

private:
    static NapiErrorManager *instance_;
    NapiOnWorkerErrorCallback onWorkerErrorCb_ { nullptr };
    NapiOnMainThreadErrorCallback onMainThreadErrorCb_ { nullptr };
    NapiAllUnhandledRejectionCallback allUnhandledRejectionCb_ { nullptr };
    NapiHasOnErrorCallback hasOnErrorCb_ { nullptr };
    NapiHasAllUnhandledRejectionCallback hasAllUnhandledRejectionCb_ { nullptr };
    napi_callback globalUnhandledRejectionCheckCb_ { nullptr };
};

bool DumpHybridStack(const EcmaVM* vm, std::string &stack, uint32_t ignored = 0, int32_t deepth = -1);

class TryCatch : public panda::TryCatch {
public:
    explicit TryCatch(napi_env env)
        : panda::TryCatch(reinterpret_cast<NativeEngine*>(env)->GetEcmaVm()),
          engine_(reinterpret_cast<NativeEngine*>(env)) {}

    ~TryCatch()
    {
        if (HasCaught()) {
            engine_->lastException_ = GetException();
        }
    }
private:
   NativeEngine* engine_ = nullptr;
};

class WorkerRunningScope {
public:
    explicit WorkerRunningScope(napi_env env) : env_(env)
    {
        auto engine = reinterpret_cast<NativeEngine*>(env_);
        engine->GetWorkerThreadState()->NoityTaskStart();
    }

    ~WorkerRunningScope()
    {
        auto engine = reinterpret_cast<NativeEngine*>(env_);
        engine->GetWorkerThreadState()->NotifyTaskEnd();
    }
private:
    napi_env env_;
};
#endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_ENGINE_H */