/*
 * Copyright (c) 2021-2024 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.
 */

#include "subscribe.h"
#include "pixelmap_cache_manager.h"
#include "subscriber_image_util.h"
#include "ans_inner_errors.h"
#include "ans_service_errors.h"
#include <mutex>
#include <uv.h>
#include "hitrace_util.h"
#include "notification_classification.h"

namespace OHOS {
namespace NotificationNapi {
const int32_t SUBSCRIBE_NOTIFICATION_MAX_PARA = 2;
const int32_t SUBSCRIBE_MAX_PARA = 3;
const int32_t NO_DELETE_REASON = -1;
const int32_t DISTRIBUTE_JUMP_PARA = 1;
const int32_t DISTRIBUTE_REPLY_PARA = 2;
const std::string CONSUME = "onConsume";
const std::string CANCEL = "onCancel";
const std::string UPDATE = "onUpdate";
const std::string CONNECTED = "onConnect";
const std::string DIS_CONNECTED = "onDisconnect";
const std::string DIE = "onDestroy";
const std::string DISTURB_MODE_CHANGE = "onDisturbModeChange";
const std::string DISTURB_DATE_CHANGE = "onDoNotDisturbDateChange";
const std::string DISTURB_CHANGED = "onDoNotDisturbChanged";
const std::string ENABLE_NOTIFICATION_CHANGED = "OnEnabledNotificationChanged";
const std::string ENABLE_SILENT_REMINDER_CHANGED = "OnEnabledSilentReminderChanged";
const std::string ENABLE_PRIORITY_CHANGED = "OnEnabledPriorityChanged";
const std::string ENABLE_PRIORITY_BY_BUNDLE_CHANGED = "OnEnabledPriorityByBundleChanged";
const std::string SYSTEM_UPDATE = "OnSystemUpdate";
const std::string BADGE_CHANGED = "OnBadgeChanged";
const std::string BADGE_ENABLED_CHANGED = "OnBadgeEnabledChanged";
const std::string BATCH_CANCEL = "onBatchCancel";
const std::string NOTIFICATION_SWITCH_CHANGED = "OnNotificationSwitchChanged";

enum class Type {
    UNKNOWN,
    CANCEL,
    BATCH_CANCEL,
    CONSUME,
    UPDATE,
    CONNECTED,
    DIS_CONNECTED,
    DIE,
    DISTURB_DATE_CHANGE,
    DISTURB_CHANGED,
    ENABLE_NOTIFICATION_CHANGED,
    BADGE_CHANGED,
    BADGE_ENABLED_CHANGED,
    ENABLE_PRIORITY_CHANGED,
    ENABLE_PRIORITY_BY_BUNDLE_CHANGED,
    SYSTEM_UPDATE,
    ENABLE_SILENT_REMINDER_CHANGED,
    NOTIFICATION_SWITCH_CHANGED
};

struct NotificationReceiveDataWorker {
    std::shared_ptr<OHOS::Notification::Notification> request;
    std::vector<std::shared_ptr<OHOS::Notification::Notification>> requestList;
    std::shared_ptr<NotificationSortingMap> sortingMap;
    NotificationDoNotDisturbDate date;
    EnabledNotificationCallbackData callbackData;
    EnabledSilentReminderCallbackData silentReminderCallbackData;
    EnabledPriorityNotificationByBundleCallbackData priorityCallbackData;
    NotificationSwitchChangedCallbackData notificationSwitchChangedCallbackData;
    BadgeNumberCallbackData badge;
    int32_t deleteReason = 0;
    bool priorityEnable = false;
    int32_t result = 0;
    int32_t disturbMode = 0;
    std::weak_ptr<SubscriberInstance> subscriber;
    Type type;
};

napi_value SetSubscribeCallbackData(const napi_env &env,
    const std::shared_ptr<OHOS::Notification::Notification> &request,
    const std::shared_ptr<NotificationSortingMap> &sortingMap, int32_t deleteReason, napi_value &result)
{
    ANS_LOGD("called");
    if (request == nullptr) {
        ANS_LOGE("null request");
        return Common::NapiGetBoolean(env, false);
    }

    // request: NotificationRequest
    napi_value requestResult = nullptr;
    napi_create_object(env, &requestResult);
    if (!Common::SetNotification(env, request.get(), requestResult)) {
        ANS_LOGE("SetNotification call failed");
        return Common::NapiGetBoolean(env, false);
    }
    napi_set_named_property(env, result, "request", requestResult);

    if (sortingMap != nullptr) {
        // sortingMap?: NotificationSortingMap
        napi_value sortingMapResult = nullptr;
        napi_create_object(env, &sortingMapResult);
        if (!Common::SetNotificationSortingMap(env, sortingMap, sortingMapResult)) {
            ANS_LOGE("SetNotificationSortingMap call failed");
            return Common::NapiGetBoolean(env, false);
        }
        napi_set_named_property(env, result, "sortingMap", sortingMapResult);
    }
    
    // reason?: number
    if (deleteReason != NO_DELETE_REASON) {
        napi_value value = nullptr;
        int32_t outReason = 0;
        if (!AnsEnumUtil::ReasonCToJS(deleteReason, outReason)) {
            return Common::NapiGetBoolean(env, false);
        }
        napi_create_int32(env, outReason, &value);
        napi_set_named_property(env, result, "reason", value);
    }

    // sound?: string
    napi_value soundResult = nullptr;
    std::string sound;
    if (request->EnableSound()) {
        sound = request->GetSound().ToString();
    }
    napi_create_string_utf8(env, sound.c_str(), NAPI_AUTO_LENGTH, &soundResult);
    napi_set_named_property(env, result, "sound", soundResult);

    // vibrationValues?: Array<number>
    napi_value arr = nullptr;
    napi_create_array(env, &arr);
    if (request->EnableVibrate()) {
        uint32_t count = 0;
        for (auto vec : request->GetVibrationStyle()) {
            napi_value nVibrationValue = nullptr;
            napi_create_int64(env, vec, &nVibrationValue);
            napi_set_element(env, arr, count, nVibrationValue);
            count++;
        }
    }
    napi_set_named_property(env, result, "vibrationValues", arr);

    // voiceContent?: {textContent: string}
    auto voiceContent = request->GetVoiceContent();
    if (voiceContent != nullptr) {
        napi_value voiceContentResult = nullptr;
        napi_create_object(env, &voiceContentResult);
        if (!Common::SetNotificationVoiceContent(env, *voiceContent, voiceContentResult)) {
            ANS_LOGE("SetNotificationVoiceContent call failed");
            return Common::NapiGetBoolean(env, false);
        }
        napi_set_named_property(env, result, "voiceContent", voiceContentResult);
    }

    // notificationClassification
    auto notificationClassification = request->GetNotificationClassification();
    if (notificationClassification != nullptr) {
        napi_value notificationClassificationNapi = nullptr;
        napi_create_object(env, &notificationClassificationNapi);
        if (!Common::SetNotificationClassification(env, *notificationClassification, notificationClassificationNapi)) {
            ANS_LOGE("SetNotificationClassification call failed");
            return Common::NapiGetBoolean(env, false);
        }
        napi_set_named_property(env, result, "notificationClassification", notificationClassificationNapi);
    }
    return Common::NapiGetBoolean(env, true);
}

napi_value SetPriorityCallbackData(const napi_env &env, const bool enable, napi_value &result)
{
    ANS_LOGD("called");
    napi_value value = nullptr;
    napi_get_boolean(env, enable, &value);
    napi_set_named_property(env, result, "enable", value);
    return Common::NapiGetBoolean(env, true);
}

static void ClearEnvCallback(void *data)
{
    ANS_LOGD("Env expired, need to clear env");
    SubscriberInstance *subscriber = reinterpret_cast<SubscriberInstance *>(data);
    subscriber->ClearEnv();
}

SubscriberInstance::SubscriberInstance()
{}

SubscriberInstance::~SubscriberInstance()
{}

void SubscriberInstance::SubDeleteRef()
{
    if (enabledPriorityCallbackInfo_.ref != nullptr) {
        napi_delete_reference(enabledPriorityCallbackInfo_.env, enabledPriorityCallbackInfo_.ref);
        enabledPriorityCallbackInfo_.ref = nullptr;
    }
    if (enabledPriorityByBundleCallbackInfo_.ref != nullptr) {
        napi_delete_reference(enabledPriorityByBundleCallbackInfo_.env, enabledPriorityByBundleCallbackInfo_.ref);
        enabledPriorityByBundleCallbackInfo_.ref = nullptr;
    }

    if (systemUpdateCallbackInfo_.ref != nullptr) {
        napi_delete_reference(systemUpdateCallbackInfo_.env, systemUpdateCallbackInfo_.ref);
        systemUpdateCallbackInfo_.ref = nullptr;
    }

    if (notificationSwitchChangedCallbackInfo_.ref != nullptr) {
        napi_delete_reference(notificationSwitchChangedCallbackInfo_.env, notificationSwitchChangedCallbackInfo_.ref);
        notificationSwitchChangedCallbackInfo_.ref = nullptr;
    }

    if (disturbDateCallbackInfo_.ref != nullptr) {
        napi_delete_reference(disturbDateCallbackInfo_.env, disturbDateCallbackInfo_.ref);
        disturbDateCallbackInfo_.ref = nullptr;
    }

    if (disturbChangedCallbackInfo_.ref != nullptr) {
        napi_delete_reference(disturbChangedCallbackInfo_.env, disturbChangedCallbackInfo_.ref);
        disturbChangedCallbackInfo_.ref = nullptr;
    }

    if (enabledSilentReminderCallbackInfo_.ref != nullptr) {
        napi_delete_reference(enabledSilentReminderCallbackInfo_.env, enabledSilentReminderCallbackInfo_.ref);
        enabledSilentReminderCallbackInfo_.ref = nullptr;
    }

    if (setBadgeCallbackInfo_.ref != nullptr) {
        napi_delete_reference(setBadgeCallbackInfo_.env, setBadgeCallbackInfo_.ref);
        setBadgeCallbackInfo_.ref = nullptr;
    }

    if (setBadgeEnabledCallbackInfo_.ref != nullptr) {
        napi_delete_reference(setBadgeEnabledCallbackInfo_.env, setBadgeEnabledCallbackInfo_.ref);
        setBadgeEnabledCallbackInfo_.ref = nullptr;
    }
}

void SubscriberInstance::DeleteRef()
{
    {
        std::lock_guard<ffrt::mutex> lock(tsfnMutex_);
        if (tsfn_ != nullptr) {
            napi_release_threadsafe_function(tsfn_, napi_tsfn_release);
            tsfn_ = nullptr;
        }
    }
    if (canceCallbackInfo_.ref != nullptr) {
        napi_delete_reference(canceCallbackInfo_.env, canceCallbackInfo_.ref);
        canceCallbackInfo_.ref = nullptr;
    }
    if (consumeCallbackInfo_.ref != nullptr) {
        napi_delete_reference(consumeCallbackInfo_.env, consumeCallbackInfo_.ref);
        consumeCallbackInfo_.ref = nullptr;
    }
    if (updateCallbackInfo_.ref != nullptr) {
        napi_delete_reference(updateCallbackInfo_.env, updateCallbackInfo_.ref);
        updateCallbackInfo_.ref = nullptr;
    }
    if (subscribeCallbackInfo_.ref != nullptr) {
        napi_delete_reference(subscribeCallbackInfo_.env, subscribeCallbackInfo_.ref);
        subscribeCallbackInfo_.ref = nullptr;
    }
    if (unsubscribeCallbackInfo_.ref != nullptr) {
        napi_delete_reference(unsubscribeCallbackInfo_.env, unsubscribeCallbackInfo_.ref);
        unsubscribeCallbackInfo_.ref = nullptr;
    }
    if (dieCallbackInfo_.ref != nullptr) {
        napi_delete_reference(dieCallbackInfo_.env, dieCallbackInfo_.ref);
        dieCallbackInfo_.ref = nullptr;
    }
    if (disturbModeCallbackInfo_.ref != nullptr) {
        napi_delete_reference(disturbModeCallbackInfo_.env, disturbModeCallbackInfo_.ref);
        disturbModeCallbackInfo_.ref = nullptr;
    }
    if (enabledNotificationCallbackInfo_.ref != nullptr) {
        napi_delete_reference(enabledNotificationCallbackInfo_.env, enabledNotificationCallbackInfo_.ref);
        enabledNotificationCallbackInfo_.ref = nullptr;
    }
    if (batchCancelCallbackInfo_.ref != nullptr) {
        napi_delete_reference(batchCancelCallbackInfo_.env, batchCancelCallbackInfo_.ref);
        batchCancelCallbackInfo_.ref = nullptr;
    }
    SubDeleteRef();
    if (env_ != nullptr) {
        napi_remove_env_cleanup_hook(env_, ClearEnvCallback, this);
    }
}

void SubscriberInstance::ClearEnv()
{
    DeleteRef();
    env_ = nullptr;
}

void SubscriberInstance::CallThreadSafeFunc(void* data)
{
    std::lock_guard<ffrt::mutex> lock(tsfnMutex_);
    if (tsfn_ == nullptr) {
        auto dataWorker = reinterpret_cast<NotificationReceiveDataWorker *>(data);
        delete dataWorker;
        dataWorker = nullptr;
        ANS_LOGD("null tsfn_");
        return;
    }
    napi_acquire_threadsafe_function(tsfn_);
    napi_call_threadsafe_function(tsfn_, data, napi_tsfn_nonblocking);
    napi_release_threadsafe_function(tsfn_, napi_tsfn_release);
    return;
}

void ThreadSafeOnCancel(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);
    if (!SetSubscribeCallbackData(env,
        dataWorkerData->request,
        dataWorkerData->sortingMap,
        dataWorkerData->deleteReason,
        result)) {
        ANS_LOGE("Failed to convert data to JS");
    } else {
        Common::SetCallback(env, subscriber->GetCallbackInfo(CANCEL).ref, result);
    }
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnCanceled(const std::shared_ptr<OHOS::Notification::Notification> &request,
    const std::shared_ptr<NotificationSortingMap> &sortingMap, int32_t deleteReason)
{
    ANS_LOGD("called");

    if (canceCallbackInfo_.ref == nullptr || canceCallbackInfo_.env == nullptr) {
        return;
    }

    if (request == nullptr) {
        ANS_LOGE("null request");
        return;
    }

    if (sortingMap == nullptr) {
        ANS_LOGE("null sortingMap");
        return;
    }
    auto cacheManager = PixelMapCacheManager::GetInstance();
    cacheManager->RemoveCache(request->GetNotificationRequest().GetKey());
    ANS_LOGI("Cancel Key=%{public}s,sortingMap size=%{public}zu,reason=%{public}d",
        request->GetKey().c_str(), sortingMap->GetKey().size(), deleteReason);
    ANS_LOGD("SubscriberInstance::OnCanceled instanceKey: %{public}s", request->GetInstanceKey().c_str());
    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->request = request;
    dataWorker->sortingMap = sortingMap;
    dataWorker->deleteReason = deleteReason;
    dataWorker->type = Type::CANCEL;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnBatchCancel(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value resultArray = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_array(env, &resultArray);
    int index = 0;
    for (auto request : dataWorkerData->requestList) {
        napi_value result = nullptr;
        napi_create_object(env, &result);
        if (SetSubscribeCallbackData(env, request,
            dataWorkerData->sortingMap, dataWorkerData->deleteReason, result)) {
            napi_set_element(env, resultArray, index, result);
            index++;
        }
    }
    uint32_t elementCount = 0;
    napi_get_array_length(env, resultArray, &elementCount);
    ANS_LOGD("BatchCancel size:%{public}d", elementCount);
    if (elementCount > 0) {
        Common::SetCallback(env, subscriber->GetCallbackInfo(BATCH_CANCEL).ref, resultArray);
    }

    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnBatchCanceled(const std::vector<std::shared_ptr<OHOS::Notification::Notification>>
    &requestList, const std::shared_ptr<NotificationSortingMap> &sortingMap, int32_t deleteReason)
{
    if (batchCancelCallbackInfo_.ref == nullptr || batchCancelCallbackInfo_.env == nullptr) {
        return;
    }
    if (requestList.empty()) {
        ANS_LOGE("empty requestList");
        return;
    }
    if (sortingMap == nullptr) {
        ANS_LOGE("null sortingMap");
        return;
    }
    auto cacheManager = PixelMapCacheManager::GetInstance();
    std::string notificationKeys = "";
    for (auto notification : requestList) {
        notificationKeys.append(notification->GetNotificationRequest().GetKey()).append("-");
        if (notification != nullptr) {
            cacheManager->RemoveCache(notification->GetNotificationRequest().GetKey());
        }
    }
    ANS_LOGI("BatchCancel reason=%{public}d,sortingMap size=%{public}zu,keys=%{public}s",
        deleteReason, sortingMap->GetKey().size(), notificationKeys.c_str());

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }
    dataWorker->requestList = requestList;
    dataWorker->sortingMap = sortingMap;
    dataWorker->deleteReason = deleteReason;
    dataWorker->type = Type::BATCH_CANCEL;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
    return;
}

bool SubscriberInstance::HasOnBatchCancelCallback()
{
    if (batchCancelCallbackInfo_.ref == nullptr) {
        ANS_LOGE("null ref");
        return false;
    }
    return true;
}

void ThreadSafeOnConsumed(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");
    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    auto additionalData = dataWorkerData->request->GetNotificationRequest().GetAdditionalData();
    if (additionalData && additionalData->HasParam("_oh_ans_sys_traceid")) {
        std::stringstream sin(additionalData->GetStringParam("_oh_ans_sys_traceid"));
        uint64_t chainId;
        if (sin >> std::hex >> chainId) {
            TraceChainUtil traceChainUtil = TraceChainUtil();
            OHOS::HiviewDFX::HiTraceId traceId = OHOS::HiviewDFX::HiTraceChain::GetId();
            traceId.SetChainId(chainId);
            OHOS::HiviewDFX::HiTraceChain::SetId(traceId);
        }
    }
    ANS_LOGD("called");
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);
    if (!SetSubscribeCallbackData(env,
        dataWorkerData->request,
        dataWorkerData->sortingMap,
        NO_DELETE_REASON,
        result)) {
        ANS_LOGE("Convert data to JS fail.");
    } else {
        Common::SetCallback(env, subscriber->GetCallbackInfo(CONSUME).ref, result);
    }
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnConsumed(const std::shared_ptr<OHOS::Notification::Notification> &request,
    const std::shared_ptr<NotificationSortingMap> &sortingMap)
{
    ANS_LOGD("called");

    if (consumeCallbackInfo_.ref == nullptr || consumeCallbackInfo_.env == nullptr) {
        return;
    }

    if (request == nullptr) {
        ANS_LOGE("null request");
        return;
    }

    if (sortingMap == nullptr) {
        ANS_LOGE("null sortingMap");
        return;
    }
    SubscriberImageUtil::ProcessPictureOption(request, GetPictureOption());
    auto notificationFlags = request->GetNotificationRequest().GetFlags();
    ANS_LOGI("onConsume key=%{public}s n=%{public}zu flags=%{public}d",
        request->GetKey().c_str(), sortingMap->GetKey().size(),
        notificationFlags == nullptr ? -1 : static_cast<int>(notificationFlags->GetReminderFlags()));
    ANS_LOGD("OnConsumed instanceKey: %{public}s", request->GetInstanceKey().c_str());

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->request = request;
    dataWorker->sortingMap = sortingMap;
    dataWorker->type = Type::CONSUME;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnUpdate(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);
    if (!Common::SetNotificationSortingMap(env, dataWorkerData->sortingMap, result)) {
        ANS_LOGE("Failed to convert data to JS");
    } else {
        Common::SetCallback(env, subscriber->GetCallbackInfo(UPDATE).ref, result);
    }
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnUpdate(const std::shared_ptr<NotificationSortingMap> &sortingMap)
{
    ANS_LOGD("called");

    if (updateCallbackInfo_.ref == nullptr || updateCallbackInfo_.env == nullptr) {
        return;
    }

    if (sortingMap == nullptr) {
        ANS_LOGE("null sortingMap");
        return;
    }
    ANS_LOGI("update sortingMap size=%{public}zu", sortingMap->GetKey().size());

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->sortingMap = sortingMap;
    dataWorker->type = Type::UPDATE;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnConnected(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");
    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(CONNECTED).ref, Common::NapiGetNull(env));
}

void SubscriberInstance::OnConnected()
{
    ANS_LOGD("called");

    if (subscribeCallbackInfo_.ref == nullptr || subscribeCallbackInfo_.env == nullptr) {
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->type = Type::CONNECTED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnDisconnected(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData.");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    if (subscriber->GetCallbackInfo(DIS_CONNECTED).ref == nullptr) {
        ANS_LOGD("unsubscribe callback unset");
        DelSubscriberInstancesInfo(env, subscriber);
        return;
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(DIS_CONNECTED).ref, Common::NapiGetNull(env));
    DelSubscriberInstancesInfo(env, subscriber);
}

void SubscriberInstance::OnDisconnected()
{
    ANS_LOGD("called");

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->type = Type::DIS_CONNECTED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnDestroy(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    Common::SetCallback(
        env, subscriber->GetCallbackInfo(DIE).ref, Common::NapiGetNull(env));
}

void SubscriberInstance::OnDied()
{
    ANS_LOGD("called");

    if (dieCallbackInfo_.ref == nullptr) {
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->type = Type::DIE;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnDoNotDisturbDateChange(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetDoNotDisturbDate(env, dataWorkerData->date, result)) {
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(DISTURB_DATE_CHANGE).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnDoNotDisturbDateChange(const std::shared_ptr<NotificationDoNotDisturbDate> &date)
{
    ANS_LOGD("called");

    onDoNotDisturbChanged(date);

    if (disturbDateCallbackInfo_.ref == nullptr || disturbDateCallbackInfo_.env == nullptr) {
        return;
    }

    if (date == nullptr) {
        ANS_LOGE("null date");
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->date = *date;
    dataWorker->type = Type::DISTURB_DATE_CHANGE;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}


void ThreadSafeOnDoNotDisturbChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetDoNotDisturbDate(env, dataWorkerData->date, result)) {
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(DISTURB_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::onDoNotDisturbChanged(const std::shared_ptr<NotificationDoNotDisturbDate>& date)
{
    ANS_LOGD("called");

    if (disturbChangedCallbackInfo_.ref == nullptr || disturbChangedCallbackInfo_.env == nullptr) {
        return;
    }

    if (date == nullptr) {
        ANS_LOGE("null date");
        return;
    }

    NotificationReceiveDataWorker* dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->date = *date;
    dataWorker->type = Type::DISTURB_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnEnabledNotificationChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetEnabledNotificationCallbackData(env, dataWorkerData->callbackData, result)) {
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(ENABLE_NOTIFICATION_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnEnabledNotificationChanged(
    const std::shared_ptr<EnabledNotificationCallbackData> &callbackData)
{
    ANS_LOGD("called");

    if (enabledNotificationCallbackInfo_.ref == nullptr || enabledNotificationCallbackInfo_.env == nullptr) {
        return;
    }

    if (callbackData == nullptr) {
        ANS_LOGE("null callbackData");
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->callbackData = *callbackData;
    dataWorker->type = Type::ENABLE_NOTIFICATION_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnEnabledSilentReminderChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetEnabledSilentReminderCallbackData(env, dataWorkerData->silentReminderCallbackData, result)) {
        ANS_LOGE("SetEnabledSilentReminderCallbackData failed");
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(ENABLE_SILENT_REMINDER_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnEnabledSilentReminderChanged(
    const std::shared_ptr<EnabledSilentReminderCallbackData> &callbackData)
{
    ANS_LOGD("called");

    if (enabledSilentReminderCallbackInfo_.ref == nullptr || enabledSilentReminderCallbackInfo_.env == nullptr) {
        return;
    }

    if (callbackData == nullptr) {
        ANS_LOGE("null callbackData");
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->silentReminderCallbackData = *callbackData;
    dataWorker->type = Type::ENABLE_SILENT_REMINDER_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
};
void ThreadSafeOnNotificationSwitchChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetNotificationSwitchChangedCallbackData(
        env, dataWorkerData->notificationSwitchChangedCallbackData, result)) {
        ANS_LOGE("SetNotificationSwitchChangedCallbackData failed");
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(NOTIFICATION_SWITCH_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnNotificationSwitchChanged(
    const std::shared_ptr<NotificationSwitchChangedCallbackData> &callbackData)
{
    ANS_LOGD("called");

    if (notificationSwitchChangedCallbackInfo_.ref == nullptr ||
        notificationSwitchChangedCallbackInfo_.env == nullptr) {
        return;
    }

    if (callbackData == nullptr) {
        ANS_LOGE("null callbackData");
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->notificationSwitchChangedCallbackData = *callbackData;
    dataWorker->type = Type::NOTIFICATION_SWITCH_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnEnabledPriorityChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");
    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);
    if (!SetPriorityCallbackData(env, dataWorkerData->priorityEnable, result)) {
        result = Common::NapiGetNull(env);
    } else {
        Common::SetCallback(env, subscriber->GetCallbackInfo(ENABLE_PRIORITY_CHANGED).ref, result);
    }
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnEnabledPriorityChanged(const std::shared_ptr<EnabledNotificationCallbackData> &callbackData)
{
    ANS_LOGD("called");
    if (enabledPriorityCallbackInfo_.ref == nullptr || enabledPriorityCallbackInfo_.env == nullptr) {
        return;
    }
    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }
    dataWorker->priorityEnable = callbackData->GetEnable();
    dataWorker->type = Type::ENABLE_PRIORITY_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());
    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnEnabledPriorityByBundleChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetEnabledPriorityNotificationByBundleCallbackData(
        env, dataWorkerData->priorityCallbackData, result)) {
        result = Common::NapiGetNull(env);
    }
    Common::SetCallback(env, subscriber->GetCallbackInfo(ENABLE_PRIORITY_BY_BUNDLE_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnEnabledPriorityByBundleChanged(
    const std::shared_ptr<EnabledPriorityNotificationByBundleCallbackData> &callbackData)
{
    ANS_LOGD("called");
    if (enabledPriorityByBundleCallbackInfo_.ref == nullptr || enabledPriorityByBundleCallbackInfo_.env == nullptr) {
        return;
    }
    if (callbackData == nullptr) {
        ANS_LOGE("null callbackData");
        return;
    }
    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }
    dataWorker->priorityCallbackData = *callbackData;
    dataWorker->type = Type::ENABLE_PRIORITY_BY_BUNDLE_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());
    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnSystemUpdate(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);
    if (!SetSubscribeCallbackData(env, dataWorkerData->request, nullptr, NO_DELETE_REASON, result)) {
        ANS_LOGE("Convert data to JS fail.");
    } else {
        Common::SetCallback(env, subscriber->GetCallbackInfo(SYSTEM_UPDATE).ref, result);
    }
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnSystemUpdate(const std::shared_ptr<OHOS::Notification::Notification> &request)
{
    ANS_LOGD("called");
    if (systemUpdateCallbackInfo_.ref == nullptr || systemUpdateCallbackInfo_.env == nullptr) {
        return;
    }
    if (request == nullptr) {
        ANS_LOGE("OnSystemUpdate fail, null request");
        return;
    }
    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }
    dataWorker->request = request;
    dataWorker->type = Type::SYSTEM_UPDATE;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());
    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnBadgeChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);

    if (!Common::SetBadgeCallbackData(env, dataWorkerData->badge, result)) {
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(BADGE_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnBadgeChanged(
    const std::shared_ptr<BadgeNumberCallbackData> &badgeData)
{
    ANS_LOGD("called");

    if (setBadgeCallbackInfo_.ref == nullptr || setBadgeCallbackInfo_.env == nullptr) {
        return;
    }

    if (badgeData == nullptr) {
        ANS_LOGE("null badgeData");
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }
    ANS_LOGI("badgeChg %{public}s uid=%{public}d n=%{public}d",
        badgeData->GetBundle().c_str(), badgeData->GetUid(), badgeData->GetBadgeNumber());
    dataWorker->badge = *badgeData;
    dataWorker->type = Type::BADGE_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void ThreadSafeOnBadgeEnabledChanged(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");

    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    if (dataWorkerData == nullptr) {
        ANS_LOGE("null dataWorkerData");
        return;
    }
    auto subscriber = dataWorkerData->subscriber.lock();
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return;
    }
    napi_value result = nullptr;
    napi_handle_scope scope;
    auto status = napi_open_handle_scope(env, &scope);
    if (status != napi_ok || scope == nullptr) {
        ANS_LOGE("status: %{public}d", status);
        return;
    }
    napi_create_object(env, &result);
    if (!Common::SetEnabledNotificationCallbackData(env, dataWorkerData->callbackData, result)) {
        result = Common::NapiGetNull(env);
    }

    Common::SetCallback(env, subscriber->GetCallbackInfo(BADGE_ENABLED_CHANGED).ref, result);
    napi_close_handle_scope(env, scope);
}

void SubscriberInstance::OnBadgeEnabledChanged(
    const sptr<EnabledNotificationCallbackData> &callbackData)
{
    if (setBadgeEnabledCallbackInfo_.ref == nullptr) {
        return;
    }
    if (callbackData == nullptr) {
        ANS_LOGE("null callbackData");
        return;
    }

    NotificationReceiveDataWorker *dataWorker = new (std::nothrow) NotificationReceiveDataWorker();
    if (dataWorker == nullptr) {
        ANS_LOGE("null dataWorker");
        return;
    }

    dataWorker->callbackData = *callbackData;
    dataWorker->type = Type::BADGE_ENABLED_CHANGED;
    dataWorker->subscriber = std::static_pointer_cast<SubscriberInstance>(shared_from_this());

    CallThreadSafeFunc(dataWorker);
}

void SubscriberInstance::SetThreadSafeFunction(const napi_threadsafe_function &tsfn)
{
    std::lock_guard<ffrt::mutex> lock(tsfnMutex_);
    tsfn_ = tsfn;
}

void SubscriberInstance::SetEnv(const napi_env &env)
{
    env_ = env;
}

void SubscriberInstance::SetCancelCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    canceCallbackInfo_.env = env;
    canceCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetCancelCallbackInfo()
{
    return canceCallbackInfo_;
}

void SubscriberInstance::SetConsumeCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    consumeCallbackInfo_.env = env;
    consumeCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetConsumeCallbackInfo()
{
    return consumeCallbackInfo_;
}

void SubscriberInstance::SetUpdateCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    updateCallbackInfo_.env = env;
    updateCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetUpdateCallbackInfo()
{
    return updateCallbackInfo_;
}

void SubscriberInstance::SetSubscribeCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    subscribeCallbackInfo_.env = env;
    subscribeCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetSubscribeCallbackInfo()
{
    return subscribeCallbackInfo_;
}

void SubscriberInstance::SetUnsubscribeCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    unsubscribeCallbackInfo_.env = env;
    unsubscribeCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetUnsubscribeCallbackInfo()
{
    return unsubscribeCallbackInfo_;
}

void SubscriberInstance::SetDieCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    dieCallbackInfo_.env = env;
    dieCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetDieCallbackInfo()
{
    return dieCallbackInfo_;
}

void SubscriberInstance::SetDisturbModeCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    disturbModeCallbackInfo_.env = env;
    disturbModeCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetDisturbModeCallbackInfo()
{
    return disturbModeCallbackInfo_;
}

void SubscriberInstance::SetEnabledNotificationCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    enabledNotificationCallbackInfo_.env = env;
    enabledNotificationCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetEnabledNotificationCallbackInfo()
{
    return enabledNotificationCallbackInfo_;
}

void SubscriberInstance::SetEnabledSilentReminderCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    enabledSilentReminderCallbackInfo_.env = env;
    enabledSilentReminderCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetEnabledSilentReminderCallbackInfo()
{
    return enabledSilentReminderCallbackInfo_;
}

void SubscriberInstance::SetNotificationSwitchChangedCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    notificationSwitchChangedCallbackInfo_.env = env;
    notificationSwitchChangedCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetNotificationSwitchChangedCallbackInfo()
{
    return notificationSwitchChangedCallbackInfo_;
}

void SubscriberInstance::SetEnabledPriorityCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    enabledPriorityCallbackInfo_.env = env;
    enabledPriorityCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetEnabledPriorityCallbackInfo()
{
    return enabledPriorityCallbackInfo_;
}

void SubscriberInstance::SetEnabledPriorityByBundleCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    enabledPriorityByBundleCallbackInfo_.env = env;
    enabledPriorityByBundleCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetEnabledPriorityByBundleCallbackInfo()
{
    return enabledPriorityByBundleCallbackInfo_;
}

void SubscriberInstance::SetSystemUpdateCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    systemUpdateCallbackInfo_.env = env;
    systemUpdateCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetSystemUpdateCallbackInfo()
{
    return systemUpdateCallbackInfo_;
}

void SubscriberInstance::SetDisturbDateCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    disturbDateCallbackInfo_.env = env;
    disturbDateCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetDisturbDateCallbackInfo()
{
    return disturbDateCallbackInfo_;
}

void SubscriberInstance::SetDisturbChangedCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    disturbChangedCallbackInfo_.env = env;
    disturbChangedCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetDisturbChangedCallbackInfo()
{
    return disturbChangedCallbackInfo_;
}

void SubscriberInstance::SetBadgeCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    setBadgeCallbackInfo_.env = env;
    setBadgeCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetBadgeCallbackInfo()
{
    return setBadgeCallbackInfo_;
}

void SubscriberInstance::SetBadgeEnabledCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    setBadgeEnabledCallbackInfo_.env = env;
    setBadgeEnabledCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetBadgeEnabledCallbackInfo()
{
    return setBadgeEnabledCallbackInfo_;
}

void SubscriberInstance::SetBatchCancelCallbackInfo(const napi_env &env, const napi_ref &ref)
{
    batchCancelCallbackInfo_.env = env;
    batchCancelCallbackInfo_.ref = ref;
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetBatchCancelCallbackInfo()
{
    return batchCancelCallbackInfo_;
}

void SubscriberInstance::SetCallbackInfo(const napi_env &env, const std::string &type, const napi_ref &ref)
{
    ANS_LOGI("subscriber set %{public}s callback", type.c_str());
    if (type == CONSUME) {
        SetConsumeCallbackInfo(env, ref);
    } else if (type == CANCEL) {
        SetCancelCallbackInfo(env, ref);
    } else if (type == UPDATE) {
        SetUpdateCallbackInfo(env, ref);
    } else if (type == CONNECTED) {
        SetSubscribeCallbackInfo(env, ref);
    } else if (type == DIS_CONNECTED) {
        SetUnsubscribeCallbackInfo(env, ref);
    } else if (type == DIE) {
        SetDieCallbackInfo(env, ref);
    } else if (type == DISTURB_MODE_CHANGE) {
        SetDisturbModeCallbackInfo(env, ref);
    } else if (type == DISTURB_DATE_CHANGE) {
        SetDisturbDateCallbackInfo(env, ref);
    } else if (type == DISTURB_CHANGED) {
        SetDisturbChangedCallbackInfo(env, ref);
    } else if (type == ENABLE_NOTIFICATION_CHANGED) {
        SetEnabledNotificationCallbackInfo(env, ref);
    } else if (type == BADGE_CHANGED) {
        SetBadgeCallbackInfo(env, ref);
    } else if (type == BADGE_ENABLED_CHANGED) {
        SetBadgeEnabledCallbackInfo(env, ref);
    } else if (type == BATCH_CANCEL) {
        SetBatchCancelCallbackInfo(env, ref);
    } else if (type == ENABLE_PRIORITY_CHANGED) {
        SetEnabledPriorityCallbackInfo(env, ref);
    } else if (type == ENABLE_PRIORITY_BY_BUNDLE_CHANGED) {
        SetEnabledPriorityByBundleCallbackInfo(env, ref);
    } else if (type == SYSTEM_UPDATE) {
        SetSystemUpdateCallbackInfo(env, ref);
    } else if (type == ENABLE_SILENT_REMINDER_CHANGED) {
        SetEnabledSilentReminderCallbackInfo(env, ref);
    } else if (type == NOTIFICATION_SWITCH_CHANGED) {
        SetNotificationSwitchChangedCallbackInfo(env, ref);
    } else {
        ANS_LOGW("type is error");
    }
}

SubscriberInstance::CallbackInfo SubscriberInstance::GetCallbackInfo(const std::string &type)
{
    if (type == CONSUME) {
        return GetConsumeCallbackInfo();
    } else if (type == CANCEL) {
        return GetCancelCallbackInfo();
    } else if (type == UPDATE) {
        return GetUpdateCallbackInfo();
    } else if (type == CONNECTED) {
        return GetSubscribeCallbackInfo();
    } else if (type == DIS_CONNECTED) {
        return GetUnsubscribeCallbackInfo();
    } else if (type == DIE) {
        return GetDieCallbackInfo();
    } else if (type == DISTURB_MODE_CHANGE) {
        return GetDisturbModeCallbackInfo();
    } else if (type == DISTURB_DATE_CHANGE) {
        return GetDisturbDateCallbackInfo();
    } else if (type == DISTURB_CHANGED) {
        return GetDisturbChangedCallbackInfo();
    } else if (type == ENABLE_NOTIFICATION_CHANGED) {
        return GetEnabledNotificationCallbackInfo();
    } else if (type == BADGE_CHANGED) {
        return GetBadgeCallbackInfo();
    } else if (type == BADGE_ENABLED_CHANGED) {
        return GetBadgeEnabledCallbackInfo();
    } else if (type == BATCH_CANCEL) {
        return GetBatchCancelCallbackInfo();
    } else if (type == ENABLE_PRIORITY_CHANGED) {
        return GetEnabledPriorityCallbackInfo();
    } else if (type == ENABLE_PRIORITY_BY_BUNDLE_CHANGED) {
        return GetEnabledPriorityByBundleCallbackInfo();
    } else if (type == SYSTEM_UPDATE) {
        return GetSystemUpdateCallbackInfo();
    } else if (type == ENABLE_SILENT_REMINDER_CHANGED) {
        return GetEnabledSilentReminderCallbackInfo();
    } else if (type == NOTIFICATION_SWITCH_CHANGED) {
        return GetNotificationSwitchChangedCallbackInfo();
    } else {
        ANS_LOGW("type is error");
        return {nullptr, nullptr};
    }
}

bool HasNotificationSubscriber(const napi_env &env, const napi_value &value, SubscriberInstancesInfo &subscriberInfo)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto vec : subscriberInstances_) {
        napi_value callback = nullptr;
        napi_get_reference_value(env, vec.ref, &callback);
        if (value == nullptr || callback == nullptr) {
            continue;
        }
        bool isEquals = false;
        napi_strict_equals(env, value, callback, &isEquals);
        if (isEquals) {
            subscriberInfo = vec;
            return true;
        }
    }
    return false;
}

void ThreadFinished(napi_env env, void* data, [[maybe_unused]] void* context)
{
    ANS_LOGD("called");
}

void SubThreadSafeCommon(napi_env env, napi_value jsCallback, void* context, void* data, Type type)
{
    switch (type) {
        case Type::ENABLE_PRIORITY_CHANGED:
            ThreadSafeOnEnabledPriorityChanged(env, jsCallback, context, data);
            break;
        case Type::ENABLE_PRIORITY_BY_BUNDLE_CHANGED:
            ThreadSafeOnEnabledPriorityByBundleChanged(env, jsCallback, context, data);
            break;
        case Type::SYSTEM_UPDATE:
            ThreadSafeOnSystemUpdate(env, jsCallback, context, data);
            break;
        default:
            break;
    }
}

void ThreadSafeCommon(napi_env env, napi_value jsCallback, void* context, void* data)
{
    ANS_LOGD("called");
    auto dataWorkerData = reinterpret_cast<NotificationReceiveDataWorker *>(data);
    switch (dataWorkerData->type) {
        case Type::CANCEL:
            ThreadSafeOnCancel(env, jsCallback, context, data);
            break;
        case Type::BATCH_CANCEL:
            ThreadSafeOnBatchCancel(env, jsCallback, context, data);
            break;
        case Type::CONSUME:
            ThreadSafeOnConsumed(env, jsCallback, context, data);
            break;
        case Type::UPDATE:
            ThreadSafeOnUpdate(env, jsCallback, context, data);
            break;
        case Type::CONNECTED:
            ThreadSafeOnConnected(env, jsCallback, context, data);
            break;
        case Type::DIS_CONNECTED:
            ThreadSafeOnDisconnected(env, jsCallback, context, data);
            break;
        case Type::DIE:
            ThreadSafeOnDestroy(env, jsCallback, context, data);
            break;
        case Type::DISTURB_DATE_CHANGE:
            ThreadSafeOnDoNotDisturbDateChange(env, jsCallback, context, data);
            break;
        case Type::DISTURB_CHANGED:
            ThreadSafeOnDoNotDisturbChanged(env, jsCallback, context, data);
            break;
        case Type::ENABLE_NOTIFICATION_CHANGED:
            ThreadSafeOnEnabledNotificationChanged(env, jsCallback, context, data);
            break;
        case Type::BADGE_CHANGED:
            ThreadSafeOnBadgeChanged(env, jsCallback, context, data);
            break;
        case Type::BADGE_ENABLED_CHANGED:
            ThreadSafeOnBadgeEnabledChanged(env, jsCallback, context, data);
            break;
        case Type::ENABLE_SILENT_REMINDER_CHANGED:
            ThreadSafeOnEnabledSilentReminderChanged(env, jsCallback, context, data);
            break;
        case Type::NOTIFICATION_SWITCH_CHANGED:
            ThreadSafeOnNotificationSwitchChanged(env, jsCallback, context, data);
            break;
        default:
            break;
    }
    SubThreadSafeCommon(env, jsCallback, context, data, dataWorkerData->type);
    delete dataWorkerData;
    dataWorkerData = nullptr;
}

napi_value GetNotificationSubscriber(
    const napi_env &env, const napi_value &value, SubscriberInstancesInfo &subscriberInfo)
{
    ANS_LOGD("called");
    bool hasProperty = false;
    napi_valuetype valuetype = napi_undefined;
    napi_ref result = nullptr;

    subscriberInfo.subscriber = std::make_shared<SubscriberInstance>();
    if (subscriberInfo.subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        std::string msg = "Mandatory parameters are left unspecified. subscriber is null";
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
        return nullptr;
    }

    struct SubscriberGuard {
        const napi_env env;
        SubscriberInstancesInfo &info;
        bool active = true;
        ~SubscriberGuard()
        {
            if (active) {
                info.subscriber->DeleteRef();
                if (info.ref != nullptr) {
                    napi_delete_reference(env, info.ref);
                    info.ref = nullptr;
                }
                info.subscriber = nullptr;
            }
        }
    } guard {env, subscriberInfo};

    napi_create_reference(env, value, 1, &subscriberInfo.ref);

    napi_value resourceName = nullptr;
    napi_create_string_latin1(env, "tsfn", NAPI_AUTO_LENGTH, &resourceName);
    napi_threadsafe_function tsfn = nullptr;
    napi_create_threadsafe_function(env, nullptr, nullptr, resourceName, 0, 1, subscriberInfo.ref,
        ThreadFinished, nullptr, ThreadSafeCommon, &tsfn);
    subscriberInfo.subscriber->SetThreadSafeFunction(tsfn);
    subscriberInfo.subscriber->SetEnv(env);
    // default to release napi_ref callback to avoid memory-leak
    uint32_t subscribedFlag = NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_DISCONNECTED;

    // onConsume?:(data: SubscribeCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onConsume", &hasProperty));
    if (hasProperty) {
        napi_value nOnConsumed = nullptr;
        napi_get_named_property(env, value, "onConsume", &nOnConsumed);
        NAPI_CALL(env, napi_typeof(env, nOnConsumed, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnConsumed, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, CONSUME, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_CONSUMED;
    }
    // onCancel?:(data: SubscribeCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onCancel", &hasProperty));
    if (hasProperty) {
        napi_value nOnCanceled = nullptr;
        napi_get_named_property(env, value, "onCancel", &nOnCanceled);
        NAPI_CALL(env, napi_typeof(env, nOnCanceled, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnCanceled, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, CANCEL, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_CANCELED;
    }
    // onUpdate?:(data: NotificationSortingMap) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onUpdate", &hasProperty));
    if (hasProperty) {
        napi_value nOnUpdate = nullptr;
        napi_get_named_property(env, value, "onUpdate", &nOnUpdate);
        NAPI_CALL(env, napi_typeof(env, nOnUpdate, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnUpdate, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, UPDATE, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_UPDATE;
    }
    // onConnect?:() => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onConnect", &hasProperty));
    if (hasProperty) {
        napi_value nOnConnected = nullptr;
        napi_get_named_property(env, value, "onConnect", &nOnConnected);
        NAPI_CALL(env, napi_typeof(env, nOnConnected, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnConnected, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, CONNECTED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_CONNECTED;
    }
    // onDisconnect?:() => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onDisconnect", &hasProperty));
    if (hasProperty) {
        napi_value nOnDisConnect = nullptr;
        napi_get_named_property(env, value, "onDisconnect", &nOnDisConnect);
        NAPI_CALL(env, napi_typeof(env, nOnDisConnect, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnDisConnect, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, DIS_CONNECTED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_DISCONNECTED;
    }
    // onDestroy?:() => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onDestroy", &hasProperty));
    if (hasProperty) {
        napi_value nOnDied = nullptr;
        napi_get_named_property(env, value, "onDestroy", &nOnDied);
        NAPI_CALL(env, napi_typeof(env, nOnDied, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnDied, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, DIE, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_DIED;
    }
    // onDisturbModeChange?:(mode: notification.DoNotDisturbMode) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onDisturbModeChange", &hasProperty));
    if (hasProperty) {
        napi_value nOnDisturbModeChanged = nullptr;
        napi_get_named_property(env, value, "onDisturbModeChange", &nOnDisturbModeChanged);
        NAPI_CALL(env, napi_typeof(env, nOnDisturbModeChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnDisturbModeChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, DISTURB_MODE_CHANGE, result);
    }

    // onDoNotDisturbDateChange?:(mode: notification.DoNotDisturbDate) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onDoNotDisturbDateChange", &hasProperty));
    if (hasProperty) {
        napi_value nOnDisturbDateChanged = nullptr;
        napi_get_named_property(env, value, "onDoNotDisturbDateChange", &nOnDisturbDateChanged);
        NAPI_CALL(env, napi_typeof(env, nOnDisturbDateChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnDisturbDateChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, DISTURB_DATE_CHANGE, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_DONOTDISTURBDATA_CHANGED;
    }

    // onDoNotDisturbChanged?:(mode: notificationManager.DoNotDisturbDate) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onDoNotDisturbChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnDoNotDisturbChanged = nullptr;
        napi_get_named_property(env, value, "onDoNotDisturbChanged", &nOnDoNotDisturbChanged);
        NAPI_CALL(env, napi_typeof(env, nOnDoNotDisturbChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnDoNotDisturbChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, DISTURB_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_DONOTDISTURBDATA_CHANGED;
    }

    // onEnabledNotificationChanged?:(data: notification.EnabledNotificationCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onEnabledNotificationChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnEnabledNotificationChanged = nullptr;
        napi_get_named_property(env, value, "onEnabledNotificationChanged", &nOnEnabledNotificationChanged);
        NAPI_CALL(env, napi_typeof(env, nOnEnabledNotificationChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnEnabledNotificationChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, ENABLE_NOTIFICATION_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_ENABLENOTIFICATION_CHANGED;
    }

    // onEnabledSilentReminderChanged?:(data: notification.EnabledSilentReminderCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onEnabledSilentReminderChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnEnabledSilentReminderChanged = nullptr;
        napi_get_named_property(env, value, "onEnabledSilentReminderChanged", &nOnEnabledSilentReminderChanged);
        NAPI_CALL(env, napi_typeof(env, nOnEnabledSilentReminderChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnEnabledSilentReminderChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, ENABLE_SILENT_REMINDER_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_ENABLEDSILENTREMINDER_CHANGED;
    }

    // onNotificationSwitchChanged?: (callbackData: NotificationSwitchChangedCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onNotificationSwitchChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnNotificationSwitchChanged = nullptr;
        napi_get_named_property(env, value, "onNotificationSwitchChanged", &nOnNotificationSwitchChanged);
        NAPI_CALL(env, napi_typeof(env, nOnNotificationSwitchChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnNotificationSwitchChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, NOTIFICATION_SWITCH_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_NOTIFICATION_SWITCH_CHANGED;
    }

    // onEnabledPriorityChanged?: (enable: boolean) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onEnabledPriorityChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnEnabledPriorityChanged = nullptr;
        napi_get_named_property(env, value, "onEnabledPriorityChanged", &nOnEnabledPriorityChanged);
        NAPI_CALL(env, napi_typeof(env, nOnEnabledPriorityChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnEnabledPriorityChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, ENABLE_PRIORITY_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_ENABLEPRIORITY_CHANGED;
    }

    // onEnabledPriorityByBundleChanged?: (callbackData: EnabledNotificationCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onEnabledPriorityByBundleChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnEnabledPriorityByBundleChanged = nullptr;
        napi_get_named_property(env, value, "onEnabledPriorityByBundleChanged", &nOnEnabledPriorityByBundleChanged);
        NAPI_CALL(env, napi_typeof(env, nOnEnabledPriorityByBundleChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnEnabledPriorityByBundleChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, ENABLE_PRIORITY_BY_BUNDLE_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_ENABLEPRIORITYBYBUNDLE_CHANGED;
    }

    // onSystemUpdate?:(data: SubscribeCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onSystemUpdate", &hasProperty));
    if (hasProperty) {
        napi_value nOnSystemUpdate = nullptr;
        napi_get_named_property(env, value, "onSystemUpdate", &nOnSystemUpdate);
        NAPI_CALL(env, napi_typeof(env, nOnSystemUpdate, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnSystemUpdate, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, SYSTEM_UPDATE, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_SYSTEM_UPDATE;
    }

    // onBadgeChanged?:(data: BadgeNumberCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onBadgeChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnBadgeChanged = nullptr;
        napi_get_named_property(env, value, "onBadgeChanged", &nOnBadgeChanged);
        NAPI_CALL(env, napi_typeof(env, nOnBadgeChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnBadgeChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, BADGE_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_BADGE_CHANGED;
    }

    // onBadgeEnabledChanged?:(data: EnabledNotificationCallbackData) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onBadgeEnabledChanged", &hasProperty));
    if (hasProperty) {
        napi_value nOnBadgeEnabledChanged = nullptr;
        napi_get_named_property(env, value, "onBadgeEnabledChanged", &nOnBadgeEnabledChanged);
        NAPI_CALL(env, napi_typeof(env, nOnBadgeEnabledChanged, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, nOnBadgeEnabledChanged, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, BADGE_ENABLED_CHANGED, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_BADGEENABLE_CHANGED;
    }

    // onBatchCancel?:(data: Array<SubscribeCallbackData>) => void
    NAPI_CALL(env, napi_has_named_property(env, value, "onBatchCancel", &hasProperty));
    if (hasProperty) {
        napi_value onBatchCancel = nullptr;
        napi_get_named_property(env, value, "onBatchCancel", &onBatchCancel);
        NAPI_CALL(env, napi_typeof(env, onBatchCancel, &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Wrong argument type. Function expected.");
            std::string msg = "Incorrect parameter types.The type of param must be function.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        napi_create_reference(env, onBatchCancel, 1, &result);
        subscriberInfo.subscriber->SetCallbackInfo(env, BATCH_CANCEL, result);
        subscribedFlag |= NotificationConstant::SubscribedFlag::SUBSCRIBE_ON_BATCHCANCELED;
    }
    subscriberInfo.subscriber->SetSubscribedFlags(subscribedFlag);
    guard.active = false;
    return Common::NapiGetNull(env);
}

bool AddSubscriberInstancesInfo(const napi_env &env, const SubscriberInstancesInfo &subscriberInfo)
{
    ANS_LOGD("called");
    if (subscriberInfo.ref == nullptr) {
        ANS_LOGE("null ref");
        return false;
    }
    if (subscriberInfo.subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return false;
    }
    std::lock_guard<ffrt::mutex> lock(mutex_);
    subscriberInstances_.emplace_back(subscriberInfo);

    return true;
}

bool DelSubscriberInstancesInfo(const napi_env &env, const std::shared_ptr<SubscriberInstance> subscriber)
{
    ANS_LOGD("called");
    if (subscriber == nullptr) {
        ANS_LOGE("null subscriber");
        return false;
    }

    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto it = subscriberInstances_.begin(); it != subscriberInstances_.end(); ++it) {
        if (it->subscriber == subscriber) {
            DelDeletingSubscriber(it->subscriber);
            napi_delete_reference(env, it->ref);
            subscriber->DeleteRef();
            subscriberInstances_.erase(it);
            return true;
        }
    }
    return false;
}
napi_value ParseParameters(const napi_env &env, const napi_callback_info &info,
    NotificationSubscribeInfo &subscriberInfo, std::shared_ptr<SubscriberInstance> &subscriber, napi_ref &callback)
{
    size_t argc = SUBSCRIBE_MAX_PARA;
    napi_value argv[SUBSCRIBE_MAX_PARA] = {nullptr};
    napi_value thisVar = nullptr;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
    if (argc < 1) {
        ANS_LOGE("Wrong number of arguments");
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
        return nullptr;
    }

    napi_valuetype valuetype = napi_undefined;

    // argv[0]:subscriber
    NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
    if (valuetype != napi_object) {
        ANS_LOGE("Wrong argument type for arg0. NotificationSubscriber object expected.");
        std::string msg = "Incorrect parameter types.The type of param must be NotificationSubscriber.";
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
        return nullptr;
    }

    SubscriberInstancesInfo subscriberInstancesInfo;
    if (!HasNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo)) {
        if (GetNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo) == nullptr) {
            ANS_LOGE("NotificationSubscriber parse failed");
            return nullptr;
        }
        if (!AddSubscriberInstancesInfo(env, subscriberInstancesInfo)) {
            ANS_LOGE("AddSubscriberInstancesInfo add failed");
            subscriberInstancesInfo.subscriber->DeleteRef();
            if (subscriberInstancesInfo.ref != nullptr) {
                napi_delete_reference(env, subscriberInstancesInfo.ref);
                subscriberInstancesInfo.ref = nullptr;
            }
            subscriberInstancesInfo.subscriber = nullptr;
            return nullptr;
        }
    }
    subscriber = subscriberInstancesInfo.subscriber;

    // argv[1]:callback or NotificationSubscribeInfo
    if (argc >= SUBSCRIBE_MAX_PARA - 1) {
        NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
        if ((valuetype != napi_function) && (valuetype != napi_object)) {
            ANS_LOGE("Wrong argument type for arg1."
                "Function or NotificationSubscribeInfo object expected. Excute promise");
            return Common::NapiGetNull(env);
        }
        if (valuetype == napi_function) {
            napi_create_reference(env, argv[PARAM1], 1, &callback);
        } else {
            if (Common::GetNotificationSubscriberInfo(env, argv[PARAM1], subscriberInfo) == nullptr) {
                ANS_LOGE("NotificationSubscribeInfo parse failed");
                return nullptr;
            }
        }
    }

    // argv[2]:callback
    if (argc >= SUBSCRIBE_MAX_PARA) {
        NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
        if (valuetype != napi_function) {
            ANS_LOGE("Callback is not function enforce promise.");
            return Common::NapiGetNull(env);
        }
        napi_create_reference(env, argv[PARAM2], 1, &callback);
    }

    return Common::NapiGetNull(env);
}

napi_value ParseParameters(const napi_env &env, const napi_callback_info &info,
    NotificationSubscribeInfo &subscriberInfo, std::shared_ptr<SubscriberInstance> &subscriber)
{
    size_t argc = SUBSCRIBE_NOTIFICATION_MAX_PARA;
    napi_value argv[SUBSCRIBE_NOTIFICATION_MAX_PARA] = {nullptr};
    napi_value thisVar = nullptr;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
    if (argc < 1) {
        ANS_LOGE("Wrong number of arguments");
        return nullptr;
    }
    napi_valuetype valuetype = napi_undefined;
    // argv[0]:subscriber
    NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
    if (valuetype != napi_object) {
        ANS_LOGE("Wrong argument type for arg0. NotificationSubscriber object expected.");
        return nullptr;
    }
    SubscriberInstancesInfo subscriberInstancesInfo;
    if (!HasNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo)) {
        if (GetNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo) == nullptr) {
            ANS_LOGE("NotificationSubscriber parse failed");
            return nullptr;
        }
        if (!AddSubscriberInstancesInfo(env, subscriberInstancesInfo)) {
            ANS_LOGE("AddSubscriberInstancesInfo add failed");
            subscriberInstancesInfo.subscriber->DeleteRef();
            if (subscriberInstancesInfo.ref != nullptr) {
                napi_delete_reference(env, subscriberInstancesInfo.ref);
                subscriberInstancesInfo.ref = nullptr;
            }
            subscriberInstancesInfo.subscriber = nullptr;
            return nullptr;
        }
    }
    subscriber = subscriberInstancesInfo.subscriber;
    // argv[1]:NotificationSubscribeInfo
    if (argc >= SUBSCRIBE_NOTIFICATION_MAX_PARA) {
        NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
        if ((valuetype != napi_object)) {
            ANS_LOGE("Wrong argument type for arg1. NotificationSubscriber object expected.");
            return nullptr;
        }

        if (Common::GetNotificationSubscriberInfo(env, argv[PARAM1], subscriberInfo) == nullptr) {
            ANS_LOGE("NotificationSubscribeInfo parse failed");
            return nullptr;
        }
    }
    return Common::NapiGetNull(env);
}

napi_value Subscribe(napi_env env, napi_callback_info info)
{
    ANS_LOGD("called");

    napi_ref callback = nullptr;
    std::shared_ptr<SubscriberInstance> objectInfo = nullptr;
    NotificationSubscribeInfo subscriberInfo;
    if (ParseParameters(env, info, subscriberInfo, objectInfo, callback) == nullptr) {
        ANS_LOGD("null ParseParameters");
        return Common::NapiGetUndefined(env);
    }

    AsyncCallbackInfoSubscribe *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribe {
        .env = env, .asyncWork = nullptr, .objectInfo = objectInfo, .subscriberInfo = subscriberInfo
    };
    if (!asynccallbackinfo) {
        ANS_LOGD("null asynccallbackinfo");
        return Common::JSParaError(env, callback);
    }
    napi_value promise = nullptr;
    Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise);

    ANS_LOGD("Create subscribeNotification string.");
    napi_value resourceName = nullptr;
    napi_create_string_latin1(env, "subscribeNotification", NAPI_AUTO_LENGTH, &resourceName);
    // Asynchronous function call
    napi_status status = napi_create_async_work(env,
        nullptr,
        resourceName,
        [](napi_env env, void *data) {
            ANS_LOGD("Subscribe work excuted.");
            if (!data) {
                ANS_LOGE("Invalid asynccallbackinfo!");
                return;
            }
            auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoSubscribe *>(data);
            if (asynccallbackinfo) {
                if (asynccallbackinfo->subscriberInfo.hasSubscribeInfo) {
                    ANS_LOGD("Subscribe with NotificationSubscribeInfo excute.");
                    OHOS::Notification::NotificationSubscribeInfo subscribeInfo;
                    subscribeInfo.AddAppNames(asynccallbackinfo->subscriberInfo.bundleNames);
                    subscribeInfo.AddAppUserId(asynccallbackinfo->subscriberInfo.userId);
                    subscribeInfo.SetEnableClassification(asynccallbackinfo->subscriberInfo.enableClassification);
                    subscribeInfo.SetNeedSilentReplayOnSubscribe(
                        asynccallbackinfo->subscriberInfo.needSilentReplayOnSubscribe);
                    asynccallbackinfo->info.errorCode =
                        NotificationHelper::SubscribeNotification(*(asynccallbackinfo->objectInfo), subscribeInfo);
                } else {
                    ANS_LOGD("SubscribeNotification execute.");
                    asynccallbackinfo->info.errorCode =
                        NotificationHelper::SubscribeNotification(*(asynccallbackinfo->objectInfo));
                }
            }
        },
        [](napi_env env, napi_status status, void *data) {
            ANS_LOGD("Subscribe work complete.");
            if (!data) {
                ANS_LOGE("null data");
                return;
            }
            auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoSubscribe *>(data);
            if (asynccallbackinfo) {
                Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
                if (asynccallbackinfo->info.callback != nullptr) {
                    ANS_LOGD("Delete subscribe callback reference.");
                    napi_delete_reference(env, asynccallbackinfo->info.callback);
                }
                napi_delete_async_work(env, asynccallbackinfo->asyncWork);
                delete asynccallbackinfo;
                asynccallbackinfo = nullptr;
            }
            ANS_LOGD("Subscribe work complete end.");
        },
        (void *)asynccallbackinfo,
        &asynccallbackinfo->asyncWork);
    if (status != napi_ok) {
        ANS_LOGE("Create subscribeNotification async work failed.");
        asynccallbackinfo->info.errorCode = ERR_ANS_INNER_TASK_ERR;
        Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env));
        bool isCallback = asynccallbackinfo->info.isCallback;
        if (asynccallbackinfo->info.callback != nullptr) {
            napi_delete_reference(env, asynccallbackinfo->info.callback);
        }
        delete asynccallbackinfo;
        asynccallbackinfo = nullptr;
        return isCallback ? Common::NapiGetNull(env) : promise;
    }

    napi_add_env_cleanup_hook(env, ClearEnvCallback, objectInfo.get());
    status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
    if (status != napi_ok) {
        ANS_LOGE("Queue subscribeNotification async work failed.");
        asynccallbackinfo->info.errorCode = ERR_ANS_INNER_TASK_ERR;
        Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env));
        bool isCallback = asynccallbackinfo->info.isCallback;
        if (asynccallbackinfo->info.callback != nullptr) {
            napi_delete_reference(env, asynccallbackinfo->info.callback);
        }
        napi_delete_async_work(env, asynccallbackinfo->asyncWork);
        delete asynccallbackinfo;
        asynccallbackinfo = nullptr;
        return isCallback ? Common::NapiGetNull(env) : promise;
    }

    if (asynccallbackinfo->info.isCallback) {
        ANS_LOGD("null isCallback");
        return Common::NapiGetNull(env);
    } else {
        return promise;
    }
}

bool AddDeletingSubscriber(std::shared_ptr<SubscriberInstance> subscriber)
{
    std::lock_guard<ffrt::mutex> lock(delMutex_);
    auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber);
    if (iter != DeletingSubscriber.end()) {
        return false;
    }

    DeletingSubscriber.push_back(subscriber);
    return true;
}

void DelDeletingSubscriber(std::shared_ptr<SubscriberInstance> subscriber)
{
    std::lock_guard<ffrt::mutex> lock(delMutex_);
    auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber);
    if (iter != DeletingSubscriber.end()) {
        DeletingSubscriber.erase(iter);
    }
}

napi_value GetParamOperationInfoSub(const napi_env &env, const napi_value &content, OperationInfo& operationInfo)
{
    napi_valuetype valuetype = napi_undefined;
    napi_value result = nullptr;
    bool hasProperty = false;
    NAPI_CALL(env, napi_has_named_property(env, content, "operationType", &hasProperty));
    if (hasProperty) {
        napi_get_named_property(env, content, "operationType", &result);
        NAPI_CALL(env, napi_typeof(env, result, &valuetype));
        if (valuetype != napi_number) {
            return nullptr;
        }
        int32_t code;
        NAPI_CALL(env, napi_get_value_int32(env, result, &code));
        operationInfo.operationType = code;
    }

    NAPI_CALL(env, napi_has_named_property(env, content, "buttonIndex", &hasProperty));
    if (hasProperty) {
        napi_get_named_property(env, content, "buttonIndex", &result);
        NAPI_CALL(env, napi_typeof(env, result, &valuetype));
        if (valuetype != napi_number) {
            return nullptr;
        }

        int32_t code;
        NAPI_CALL(env, napi_get_value_int32(env, result, &code));
        operationInfo.btnIndex = code;
    }
    return Common::NapiGetNull(env);
}

napi_value GetParamOperationInfo(const napi_env &env, const napi_value &content, OperationInfo& operationInfo)
{
    operationInfo.withOperationInfo = true;
    napi_valuetype valuetype = napi_undefined;
    NAPI_CALL(env, napi_typeof(env, content, &valuetype));
    if (valuetype != napi_object) {
        ANS_LOGE("Wrong argument type for arg1. object expected.");
        std::string msg = "Incorrect parameter type. The type of operationInfo must be object.";
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
        return nullptr;
    }

    size_t strLen = 0;
    napi_value result = nullptr;
    bool hasProperty = false;
    NAPI_CALL(env, napi_has_named_property(env, content, "actionName", &hasProperty));
    if (hasProperty) {
        napi_get_named_property(env, content, "actionName", &result);
        NAPI_CALL(env, napi_typeof(env, result, &valuetype));
        if (valuetype != napi_string) {
            ANS_LOGE("Wrong argument type. String expected.");
            std::string msg = "Incorrect parameter types. The type of actionName must be string.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        char str[STR_MAX_SIZE] = {0};
        NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen));
        operationInfo.actionName = str;
    }

    NAPI_CALL(env, napi_has_named_property(env, content, "userInput", &hasProperty));
    if (hasProperty) {
        napi_get_named_property(env, content, "userInput", &result);
        NAPI_CALL(env, napi_typeof(env, result, &valuetype));
        if (valuetype != napi_string) {
            ANS_LOGE("Wrong argument type. String expected.");
            std::string msg = "Incorrect parameter types. The type of userInput must be string.";
            Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
            return nullptr;
        }
        char str[LONG_STR_MAX_SIZE] = {0};
        NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, LONG_STR_MAX_SIZE - 1, &strLen));
        operationInfo.userInput = str;
    }

    if (!operationInfo.userInput.empty()) {
        return Common::NapiGetNull(env);
    }
    return GetParamOperationInfoSub(env, content, operationInfo);
}

napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, std::string &hashCode,
    napi_value& thisVar, OperationInfo& operationInfo)
{
    ANS_LOGD("called");

    size_t argc = DISTRIBUTE_REPLY_PARA;
    napi_value argv[DISTRIBUTE_REPLY_PARA] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
    if (argc < DISTRIBUTE_JUMP_PARA) {
        ANS_LOGE("Wrong number of arguments");
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
        return nullptr;
    }

    napi_valuetype valuetype = napi_undefined;
    NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
    if (valuetype == napi_string) {
        size_t strLen = 0;
        char str[STR_MAX_SIZE] = {0};
        NAPI_CALL(env, napi_get_value_string_utf8(env, argv[PARAM0], str, STR_MAX_SIZE - 1, &strLen));
        hashCode = str;
    } else {
        ANS_LOGE("Wrong argument type for arg0. string expected.");
        std::string msg = "Incorrect parameter type. The type of hashcode must be string.";
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
        return nullptr;
    }

    if (hashCode.empty()) {
        ANS_LOGE("Wrong argument type for arg0. not empty expected.");
        std::string msg = "Incorrect parameter type. The type of hashcode must be not null.";
        Common::NapiThrowLegacy(env, ERROR_PARAM_INVALID, msg);
        return nullptr;
    }

    if (argc > DISTRIBUTE_JUMP_PARA) {
        if (GetParamOperationInfo(env, argv[PARAM1], operationInfo) == nullptr) {
            return Common::NapiGetUndefined(env);
        }
    }

    return Common::NapiGetNull(env);
}
}  // namespace NotificationNapi
}  // namespace OHOS