/*
 * Copyright (c) 2023-2025 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 "dm_native_util.h"

#include "dm_anonymous.h"
#include "dm_constants.h"
#include "dm_log.h"
#include "ipc_skeleton.h"
#include "js_native_api.h"
#include "tokenid_kit.h"

using namespace OHOS::Security::AccessToken;

namespace OHOS {
namespace DistributedHardware {
namespace {
const std::string ERR_MESSAGE_NO_PERMISSION = "Permission verify failed.";
const std::string ERR_MESSAGE_NOT_SYSTEM_APP = "The caller is not a system application.";
const std::string ERR_MESSAGE_INVALID_PARAMS = "Input parameter error.";
const std::string ERR_MESSAGE_FAILED = "Failed to execute the function.";
const std::string ERR_MESSAGE_OBTAIN_SERVICE = "Failed to obtain the service.";
const std::string ERR_MESSAGE_AUTHENTICATION_INVALID = "Authentication invalid.";
const std::string ERR_MESSAGE_DISCOVERY_INVALID = "Discovery invalid.";
const std::string ERR_MESSAGE_PUBLISH_INVALID = "Publish invalid.";
const std::string ERR_MESSAGE_FROM_CLOUD_FAILED = "Get data from cloud failed.";
const std::string ERR_MESSAGE_NEED_LOGIN = "A login account is required.";
const std::string ERR_MESSAGE_SCAS_CHECK_FAILED = "The device name contains non-compliant content.";
const std::string ERR_MESSAGE_INVALID_NETWORK_ID = "Invalid network ID.";

const int32_t DM_NAPI_DISCOVER_EXTRA_INIT_ONE = -1;
const int32_t DM_NAPI_DISCOVER_EXTRA_INIT_TWO = -2;
const int32_t DM_NAPI_DESCRIPTION_BUF_LENGTH = 16384;
const int32_t DM_NAPI_BUF_LENGTH = 256;
const int32_t MAX_OBJECT_LEN = 4096;
const std::vector<FieldMapping> FIELD_MAPPINGS = {
    {"appOperation", 0, APP_OPERATION, 0, DM_NAPI_DESCRIPTION_BUF_LENGTH, false},
    {"customDescription", 0, CUSTOM_DESCRIPTION, 0, DM_NAPI_DESCRIPTION_BUF_LENGTH, false},
    {"targetPkgName", 0, PARAM_KEY_TARGET_PKG_NAME, 0, DM_NAPI_BUF_LENGTH, false},
    {"pinCode", 0, PARAM_KEY_PIN_CODE, 0, DM_NAPI_BUF_LENGTH, false},
    {"authToken", 0, PARAM_KEY_AUTH_TOKEN, 0, DM_NAPI_BUF_LENGTH, false},
    {"isShowTrustDialog", 0, PARAM_KEY_IS_SHOW_TRUST_DIALOG, 0, DM_NAPI_BUF_LENGTH, false},
    {"screenId", 0, PARAM_KEY_SCREEN_ID, 0, DM_NAPI_BUF_LENGTH, true},
    {"screenType", 0, PARAM_KEY_SCREEN_TYPE, 0, DM_NAPI_BUF_LENGTH, true},
    {"brMac", 0, PARAM_KEY_BR_MAC, 0, DM_NAPI_BUF_LENGTH, false},
    {"bleMac", 0, PARAM_KEY_BLE_MAC, 0, DM_NAPI_BUF_LENGTH, false},
    {"wifiIP", 0, PARAM_KEY_WIFI_IP, 0, DM_NAPI_BUF_LENGTH, false},
    {"wifiPort", 1, PARAM_KEY_WIFI_PORT, -1, 0, false},
    {"bindLevel", 1, BIND_LEVEL, 0, 0, false}
};

void JsObjectToString(const napi_env &env, const napi_value &object, const std::string &fieldStr,
                      char *dest, const int32_t destLen)
{
    if (dest == nullptr || destLen < 0 || (destLen > MAX_OBJECT_LEN && fieldStr != CUSTOM_DESCRIPTION) ||
        destLen > DM_NAPI_DESCRIPTION_BUF_LENGTH) {
        return;
    }
    bool hasProperty = false;
    NAPI_CALL_RETURN_VOID(env, napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty));
    if (hasProperty) {
        napi_value field = nullptr;
        napi_valuetype valueType = napi_undefined;

        napi_get_named_property(env, object, fieldStr.c_str(), &field);
        NAPI_CALL_RETURN_VOID(env, napi_typeof(env, field, &valueType));
        if (!CheckArgsType(env, valueType == napi_string, fieldStr.c_str(), "string")) {
            return;
        }
        size_t result = 0;
        NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, field, dest, destLen, &result));
    } else {
        LOGE("devicemanager napi js to str no property: %{public}s", fieldStr.c_str());
    }
}

std::string GetStrFromJsObj(const napi_env &env, const napi_value &jsObj, const std::string &fieldStr)
{
    char str[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, jsObj, fieldStr, str, sizeof(str));
    return str;
}

void JsObjectToBool(const napi_env &env, const napi_value &object, const std::string &fieldStr,
                    bool &fieldRef)
{
    bool hasProperty = false;
    NAPI_CALL_RETURN_VOID(env, napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty));
    if (hasProperty) {
        napi_value field = nullptr;
        napi_valuetype valueType = napi_undefined;

        napi_get_named_property(env, object, fieldStr.c_str(), &field);
        NAPI_CALL_RETURN_VOID(env, napi_typeof(env, field, &valueType));
        if (!CheckArgsType(env, valueType == napi_boolean, fieldStr.c_str(), "bool")) {
            return;
        }
        napi_get_value_bool(env, field, &fieldRef);
    } else {
        LOGE("devicemanager napi js to bool no property: %{public}s", fieldStr.c_str());
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + " no property " + fieldStr;
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
    }
}

void JsObjectToInt(const napi_env &env, const napi_value &object, const std::string &fieldStr,
                   int32_t &fieldRef)
{
    bool hasProperty = false;
    NAPI_CALL_RETURN_VOID(env, napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty));
    if (hasProperty) {
        napi_value field = nullptr;
        napi_valuetype valueType = napi_undefined;

        napi_get_named_property(env, object, fieldStr.c_str(), &field);
        NAPI_CALL_RETURN_VOID(env, napi_typeof(env, field, &valueType));
        if (!CheckArgsType(env, valueType == napi_number, fieldStr.c_str(), "number")) {
            return;
        }
        napi_get_value_int32(env, field, &fieldRef);
    } else {
        LOGE("devicemanager napi js to int no property: %{public}s", fieldStr.c_str());
    }
}

int32_t GetIntFromJsObj(const napi_env &env, const napi_value &object, const std::string &fieldStr)
{
    int32_t num = 0;
    JsObjectToInt(env, object, fieldStr, num);
    return num;
}

std::string GetDeviceTypeById(DmDeviceType type)
{
    const static std::pair<DmDeviceType, std::string> mapArray[] = {
        {DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_UNKNOWN_STRING},
        {DEVICE_TYPE_PHONE, DEVICE_TYPE_PHONE_STRING},
        {DEVICE_TYPE_PAD, DEVICE_TYPE_PAD_STRING},
        {DEVICE_TYPE_TV, DEVICE_TYPE_TV_STRING},
        {DEVICE_TYPE_CAR, DEVICE_TYPE_CAR_STRING},
        {DEVICE_TYPE_WATCH, DEVICE_TYPE_WATCH_STRING},
        {DEVICE_TYPE_WIFI_CAMERA, DEVICE_TYPE_WIFICAMERA_STRING},
        {DEVICE_TYPE_PC, DEVICE_TYPE_PC_STRING},
        {DEVICE_TYPE_SMART_DISPLAY, DEVICE_TYPE_SMART_DISPLAY_STRING},
        {DEVICE_TYPE_2IN1, DEVICE_TYPE_2IN1_STRING},
        {DEVICE_TYPE_GLASSES, DEVICE_TYPE_GLASSES_STRING},
    };
    for (const auto& item : mapArray) {
        if (item.first == type) {
            return item.second;
        }
    }
    return DEVICE_TYPE_UNKNOWN_STRING;
}

bool CheckArgsVal(napi_env env, bool assertion, const std::string &param, const std::string &msg)
{
    if (!(assertion)) {
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + "The value of " + param + ": " + msg;
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
        return false;
    }
    return true;
}
}

napi_value GenerateBusinessError(napi_env env, int32_t err, const std::string &msg)
{
    napi_value businessError = nullptr;
    NAPI_CALL(env, napi_create_object(env, &businessError));
    napi_value errorCode = nullptr;
    NAPI_CALL(env, napi_create_int32(env, err, &errorCode));
    napi_value errorMessage = nullptr;
    NAPI_CALL(env, napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &errorMessage));
    NAPI_CALL(env, napi_set_named_property(env, businessError, "code", errorCode));
    NAPI_CALL(env, napi_set_named_property(env, businessError, "message", errorMessage));
    return businessError;
}

napi_value GenerateBusinessErrorSystem(napi_env env, int32_t err, const std::string &msg)
{
    napi_value businessError = nullptr;
    DM_NAPI_CALL(napi_create_object(env, &businessError), nullptr);
    napi_value errorCode = nullptr;
    DM_NAPI_CALL(napi_create_int32(env, err, &errorCode), nullptr);
    napi_value errorMessage = nullptr;
    DM_NAPI_CALL(napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &errorMessage), nullptr);
    DM_NAPI_CALL_NO_RETURN(napi_set_named_property(env, businessError, "code", errorCode));
    DM_NAPI_CALL_NO_RETURN(napi_set_named_property(env, businessError, "message", errorMessage));
    return businessError;
}

bool CheckArgsCount(napi_env env, bool assertion, const std::string &message)
{
    if (!(assertion)) {
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + message;
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
        return false;
    }
    return true;
}

bool CheckArgsType(napi_env env, bool assertion, const std::string &paramName, const std::string &type)
{
    if (!(assertion)) {
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + "The type of " + paramName +
                " must be " + type;
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
        return false;
    }
    return true;
}

napi_value CreateErrorForCall(napi_env env, int32_t code, const std::string &errMsg, bool isAsync)
{
    LOGI("code:%{public}d, message:%{public}s", code, errMsg.c_str());
    napi_value error = nullptr;
    if (isAsync) {
        napi_throw_error(env, std::to_string(code).c_str(), errMsg.c_str());
    } else {
        error = GenerateBusinessError(env, code, errMsg);
    }
    return error;
}

napi_value CreateErrorForCallSystem(napi_env env, int32_t code, const std::string &errMsg, bool isAsync)
{
    LOGI("CreateErrorForCall code:%{public}d, message:%{public}s", code, errMsg.c_str());
    napi_value error = nullptr;
    if (isAsync) {
        napi_throw_error(env, std::to_string(code).c_str(), errMsg.c_str());
    } else {
        error = GenerateBusinessErrorSystem(env, code, errMsg);
    }
    return error;
}

napi_value CreateBusinessError(napi_env env, int32_t errCode, bool isAsync)
{
    napi_value error = nullptr;
    switch (errCode) {
        case ERR_DM_NO_PERMISSION:
            error = CreateErrorForCall(env, ERR_NO_PERMISSION, ERR_MESSAGE_NO_PERMISSION, isAsync);
            break;
        case ERR_DM_DISCOVERY_REPEATED:
            error = CreateErrorForCall(env, DM_ERR_DISCOVERY_INVALID, ERR_MESSAGE_DISCOVERY_INVALID, isAsync);
            break;
        case ERR_DM_PUBLISH_REPEATED:
            error = CreateErrorForCall(env, DM_ERR_PUBLISH_INVALID, ERR_MESSAGE_PUBLISH_INVALID, isAsync);
            break;
        case ERR_DM_AUTH_BUSINESS_BUSY:
            error = CreateErrorForCall(env, DM_ERR_AUTHENTICATION_INVALID,
                ERR_MESSAGE_AUTHENTICATION_INVALID, isAsync);
            break;
        case ERR_DM_INPUT_PARA_INVALID:
        case ERR_DM_UNSUPPORTED_AUTH_TYPE:
        case ERR_DM_CALLBACK_REGISTER_FAILED:
            error = CreateErrorForCall(env, ERR_INVALID_PARAMS, ERR_MESSAGE_INVALID_PARAMS, isAsync);
            break;
        case ERR_DM_INIT_FAILED:
            error = CreateErrorForCall(env, DM_ERR_OBTAIN_SERVICE, ERR_MESSAGE_OBTAIN_SERVICE, isAsync);
            break;
        case ERR_DM_GET_OSTYPE_FAILED:
            error = CreateErrorForCall(env, DM_ERR_INVALID_NETWORK_ID, ERR_MESSAGE_INVALID_NETWORK_ID, isAsync);
            break;
        case ERR_DM_NOT_SYSTEM_APP:
            error = CreateErrorForCall(env, ERR_NOT_SYSTEM_APP, ERR_MESSAGE_NOT_SYSTEM_APP, isAsync);
            break;
        case ERR_DM_HILINKSVC_RSP_PARSE_FAILD:
        case ERR_DM_HILINKSVC_REPLY_FAILED:
        case ERR_DM_HILINKSVC_ICON_URL_EMPTY:
        case ERR_DM_HILINKSVC_DISCONNECT:
            error = CreateErrorForCall(env, DM_ERR_FROM_CLOUD_FAILED, ERR_MESSAGE_FROM_CLOUD_FAILED, isAsync);
            break;
        case ERR_DM_WISE_NEED_LOGIN:
            error = CreateErrorForCall(env, DM_ERR_NEED_LOGIN, ERR_MESSAGE_NEED_LOGIN, isAsync);
            break;
        case ERR_DM_HILINKSVC_SCAS_CHECK_FAILED:
            error = CreateErrorForCall(env, DM_ERR_SCAS_CHECK_FAILED, ERR_MESSAGE_SCAS_CHECK_FAILED, isAsync);
            break;
        default:
            error = CreateErrorForCall(env, DM_ERR_FAILED, ERR_MESSAGE_FAILED, isAsync);
            break;
    }
    return error;
}

napi_value CreateBusinessErrorSystem(napi_env env, int32_t errCode, bool isAsync)
{
    napi_value error = nullptr;
    switch (errCode) {
        case ERR_DM_NO_PERMISSION:
            error = CreateErrorForCallSystem(env, ERR_NO_PERMISSION, ERR_MESSAGE_NO_PERMISSION, isAsync);
            break;
        case ERR_DM_DISCOVERY_REPEATED:
            error = CreateErrorForCallSystem(env, DM_ERR_DISCOVERY_INVALID, ERR_MESSAGE_DISCOVERY_INVALID, isAsync);
            break;
        case ERR_DM_PUBLISH_REPEATED:
            error = CreateErrorForCallSystem(env, DM_ERR_PUBLISH_INVALID, ERR_MESSAGE_PUBLISH_INVALID, isAsync);
            break;
        case ERR_DM_AUTH_BUSINESS_BUSY:
            error = CreateErrorForCallSystem(env, DM_ERR_AUTHENTICATION_INVALID,
                ERR_MESSAGE_AUTHENTICATION_INVALID, isAsync);
            break;
        case ERR_DM_INPUT_PARA_INVALID:
        case ERR_DM_UNSUPPORTED_AUTH_TYPE:
        case ERR_DM_CALLBACK_REGISTER_FAILED:
            error = CreateErrorForCallSystem(env, ERR_INVALID_PARAMS, ERR_MESSAGE_INVALID_PARAMS, isAsync);
            break;
        case ERR_DM_INIT_FAILED:
            error = CreateErrorForCallSystem(env, DM_ERR_OBTAIN_SERVICE, ERR_MESSAGE_OBTAIN_SERVICE, isAsync);
            break;
        case ERR_NOT_SYSTEM_APP:
            error = CreateErrorForCallSystem(env, ERR_NOT_SYSTEM_APP, ERR_MESSAGE_NOT_SYSTEM_APP, isAsync);
            break;
        case ERR_DM_HILINKSVC_RSP_PARSE_FAILD:
        case ERR_DM_HILINKSVC_REPLY_FAILED:
        case ERR_DM_HILINKSVC_ICON_URL_EMPTY:
        case ERR_DM_HILINKSVC_DISCONNECT:
            error = CreateErrorForCallSystem(env, DM_ERR_FROM_CLOUD_FAILED, ERR_MESSAGE_FROM_CLOUD_FAILED, isAsync);
            break;
        case ERR_DM_WISE_NEED_LOGIN:
            error = CreateErrorForCallSystem(env, DM_ERR_NEED_LOGIN, ERR_MESSAGE_NEED_LOGIN, isAsync);
            break;
        case ERR_DM_HILINKSVC_SCAS_CHECK_FAILED:
            error = CreateErrorForCallSystem(env, DM_ERR_SCAS_CHECK_FAILED, ERR_MESSAGE_SCAS_CHECK_FAILED, isAsync);
            break;
        default:
            error = CreateErrorForCallSystem(env, DM_ERR_FAILED, ERR_MESSAGE_FAILED, isAsync);
            break;
    }
    return error;
}

bool IsFunctionType(napi_env env, napi_value value)
{
    napi_valuetype eventHandleType = napi_undefined;
    napi_typeof(env, value, &eventHandleType);
    return CheckArgsType(env, eventHandleType == napi_function, "callback", "function");
}

void SetValueUtf8String(const napi_env &env, const std::string &fieldStr, const std::string &str,
                        napi_value &result)
{
    napi_value value = nullptr;
    napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &value);
    napi_set_named_property(env, result, fieldStr.c_str(), value);
}

void SetValueInt32(const napi_env &env, const std::string &fieldStr, const int32_t intValue,
                   napi_value &result)
{
    napi_value value = nullptr;
    napi_create_int32(env, intValue, &value);
    napi_set_named_property(env, result, fieldStr.c_str(), value);
}

void DeviceBasicInfoToJsArray(const napi_env &env,
                              const std::vector<DmDeviceBasicInfo> &vecDevInfo, const int32_t idx,
                              napi_value &arrayResult)
{
    napi_value result = nullptr;
    napi_create_object(env, &result);
    DmDeviceBasicToJsObject(env, vecDevInfo[idx], result);

    napi_status status = napi_set_element(env, arrayResult, idx, result);
    if (status != napi_ok) {
        LOGE("DmDeviceBasicInfo To JsArray set element error: %{public}d", status);
    }
}

void DmDeviceBasicToJsObject(napi_env env, const DmDeviceBasicInfo &devInfo, napi_value &result)
{
    SetValueUtf8String(env, "deviceId", devInfo.deviceId, result);
    SetValueUtf8String(env, "networkId", devInfo.networkId, result);
    SetValueUtf8String(env, "deviceName", devInfo.deviceName, result);
    std::string deviceType = GetDeviceTypeById(static_cast<DmDeviceType>(devInfo.deviceTypeId));
    SetValueUtf8String(env, "deviceType", deviceType.c_str(), result);
    SetValueUtf8String(env, "extraData", devInfo.extraData.c_str(), result);
}

void JsToDmPublishInfo(const napi_env &env, const napi_value &object, DmPublishInfo &info)
{
    int32_t publishId = -1;
    JsObjectToInt(env, object, "publishId", publishId);
    info.publishId = publishId;

    int32_t mode = -1;
    JsObjectToInt(env, object, "mode", mode);
    info.mode = static_cast<DmDiscoverMode>(mode);

    int32_t freq = -1;
    JsObjectToInt(env, object, "freq", freq);
    info.freq = static_cast<DmExchangeFreq>(freq);

    JsObjectToBool(env, object, "ranging", info.ranging);
    return;
}

bool IsFieldExists(const napi_env &env, const napi_value &object, const char* fieldName)
{
    bool hasProperty = false;
    napi_has_named_property(env, object, fieldName, &hasProperty);
    return hasProperty;
}
 
void ProcessStringField(const napi_env &env, const napi_value &object, JsonObject &jsonObj,
                        const FieldMapping &field)
{
    std::vector<char> buffer(field.bufferLength, 0);
    JsObjectToString(env, object, field.name, buffer.data(), buffer.size());
    jsonObj[field.jsonKey] = std::string(buffer.data());
}
 
void ProcessIntField(const napi_env &env, const napi_value &object, JsonObject &jsonObj,
                     const FieldMapping &field)
{
    int32_t value = field.defaultValue;
    JsObjectToInt(env, object, field.name, value);
    jsonObj[field.jsonKey] = value;
}
 
void JsToBindParam(const napi_env &env, const napi_value &object, std::string &bindParam,
                   int32_t &bindType, bool &isMetaType)
{
    JsonObject jsonObj;
 
    int32_t bindTypeTemp = -1;
    JsObjectToInt(env, object, "bindType", bindTypeTemp);
    bindType = bindTypeTemp;
    jsonObj[AUTH_TYPE] = bindType;
 
    char metaType[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "metaType", metaType, sizeof(metaType));
    std::string metaTypeStr = metaType;
    isMetaType = !metaTypeStr.empty();
    jsonObj[PARAM_KEY_META_TYPE] = metaTypeStr;
 
    const size_t fieldCount = FIELD_MAPPINGS.size();
    
    for (size_t i = 0; i < fieldCount; i++) {
        const auto& field = FIELD_MAPPINGS[i];

        if (field.isOptional && !IsFieldExists(env, object, field.name)) {
            continue;
        }
        
        if (field.fieldType == 0) {
            ProcessStringField(env, object, jsonObj, field);
        } else if (field.fieldType == 1) {
            ProcessIntField(env, object, jsonObj, field);
        }
    }
 
    bindParam = jsonObj.Dump();
}

bool IsSystemApp()
{
    uint64_t tokenId = OHOS::IPCSkeleton::GetSelfTokenID();
    return OHOS::Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId);
}

bool JsToDiscoverTargetType(napi_env env, const napi_value &object, int32_t &discoverTargetType)
{
    napi_valuetype objectType = napi_undefined;
    napi_typeof(env, object, &objectType);
    if (!(CheckArgsType(env, objectType == napi_object, "discoverParameter", "object or undefined"))) {
        return false;
    }
    bool hasProperty = false;
    napi_has_named_property(env, object, "discoverTargetType", &hasProperty);
    if (hasProperty) {
        napi_value field = nullptr;
        napi_valuetype valueType = napi_undefined;
        napi_get_named_property(env, object, "discoverTargetType", &field);
        napi_typeof(env, field, &valueType);
        if (!CheckArgsType(env, valueType == napi_number, "discoverTargetType", "number")) {
            return false;
        }
        napi_get_value_int32(env, field, &discoverTargetType);
        return true;
    }
    LOGE("discoverTargetType is invalid.");
    return false;
}

void JsToDmDiscoveryExtra(const napi_env &env, const napi_value &object, std::string &extra)
{
    JsonObject jsonObj;
    int32_t availableStatus = DM_NAPI_DISCOVER_EXTRA_INIT_ONE;
    JsObjectToInt(env, object, "availableStatus", availableStatus);
    if (availableStatus != DM_NAPI_DISCOVER_EXTRA_INIT_ONE) {
        jsonObj["credible"] = availableStatus;
    }

    int32_t discoverDistance = DM_NAPI_DISCOVER_EXTRA_INIT_ONE;
    JsObjectToInt(env, object, "discoverDistance", discoverDistance);
    if (discoverDistance != DM_NAPI_DISCOVER_EXTRA_INIT_ONE) {
        jsonObj["range"] = discoverDistance;
    }

    int32_t authenticationStatus = DM_NAPI_DISCOVER_EXTRA_INIT_ONE;
    JsObjectToInt(env, object, "authenticationStatus", authenticationStatus);
    if (authenticationStatus != DM_NAPI_DISCOVER_EXTRA_INIT_ONE) {
        jsonObj["isTrusted"] = authenticationStatus;
    }

    int32_t authorizationType = DM_NAPI_DISCOVER_EXTRA_INIT_TWO;
    JsObjectToInt(env, object, "authorizationType", authorizationType);
    if (authorizationType != DM_NAPI_DISCOVER_EXTRA_INIT_TWO) {
        jsonObj["authForm"] = authorizationType;
    }

    int32_t deviceType = DM_NAPI_DISCOVER_EXTRA_INIT_ONE;
    JsObjectToInt(env, object, "deviceType", deviceType);
    if (deviceType != DM_NAPI_DISCOVER_EXTRA_INIT_ONE) {
        jsonObj["deviceType"] = deviceType;
    }
    extra = jsonObj.Dump();
    LOGI("extra :%{public}s", extra.c_str());
}

void JsToDiscoveryParam(const napi_env &env, const napi_value &object,
    std::map<std::string, std::string> &discParam)
{
    char customData[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "CUSTOM_DATA", customData, sizeof(customData));
    discParam.insert(std::pair<std::string, std::string>(PARAM_KEY_CUSTOM_DATA, customData));
    char capability[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "DISC_CAPABILITY", capability, sizeof(capability));
    discParam.insert(std::pair<std::string, std::string>(PARAM_KEY_DISC_CAPABILITY, capability));
}
void InsertMapParames(JsonObject &bindParamObj, std::map<std::string, std::string> &bindParamMap)
{
    LOGI("Insert map parames start");
    if (IsInt32(bindParamObj, AUTH_TYPE)) {
        int32_t authType = bindParamObj[AUTH_TYPE].Get<int32_t>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_AUTH_TYPE, std::to_string(authType)));
    }
    if (IsString(bindParamObj, APP_OPERATION)) {
        std::string appOperation = bindParamObj[APP_OPERATION].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_APP_OPER, appOperation));
    }
    if (IsString(bindParamObj, CUSTOM_DESCRIPTION)) {
        std::string appDescription = bindParamObj[CUSTOM_DESCRIPTION].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_APP_DESC, appDescription));
    }
    if (IsString(bindParamObj, PARAM_KEY_TARGET_PKG_NAME)) {
        std::string targetPkgName = bindParamObj[PARAM_KEY_TARGET_PKG_NAME].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_TARGET_PKG_NAME, targetPkgName));
    }
    if (IsString(bindParamObj, PARAM_KEY_META_TYPE)) {
        std::string metaType = bindParamObj[PARAM_KEY_META_TYPE].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_META_TYPE, metaType));
    }
    if (IsString(bindParamObj, PARAM_KEY_PIN_CODE)) {
        std::string pinCode = bindParamObj[PARAM_KEY_PIN_CODE].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_PIN_CODE, pinCode));
    }
    if (IsString(bindParamObj, PARAM_KEY_AUTH_TOKEN)) {
        std::string authToken = bindParamObj[PARAM_KEY_AUTH_TOKEN].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_AUTH_TOKEN, authToken));
    }
    if (IsString(bindParamObj, PARAM_KEY_IS_SHOW_TRUST_DIALOG)) {
        std::string isShowTrustDialog = bindParamObj[PARAM_KEY_IS_SHOW_TRUST_DIALOG].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_IS_SHOW_TRUST_DIALOG, isShowTrustDialog));
    }
    if (IsString(bindParamObj, PARAM_KEY_SCREEN_ID)) {
        std::string screenId = bindParamObj[PARAM_KEY_SCREEN_ID].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_SCREEN_ID, screenId));
    }
    if (IsString(bindParamObj, PARAM_KEY_SCREEN_TYPE)) {
        std::string screenType = bindParamObj[PARAM_KEY_SCREEN_TYPE].Get<std::string>();
        bindParamMap.insert(std::pair<std::string, std::string>(PARAM_KEY_SCREEN_TYPE, screenType));
    }
    if (IsInt32(bindParamObj, BIND_LEVEL)) {
        int32_t bindLevel = bindParamObj[BIND_LEVEL].Get<std::int32_t>();
        bindParamMap.insert(std::pair<std::string, std::string>(BIND_LEVEL, std::to_string(bindLevel)));
    }
}

bool JsToStringAndCheck(napi_env env, napi_value value, const std::string &valueName, std::string &strValue)
{
    napi_valuetype deviceIdType = napi_undefined;
    napi_typeof(env, value, &deviceIdType);
    if (!CheckArgsType(env, deviceIdType == napi_string, valueName, "string")) {
        return false;
    }
    size_t valueLen = 0;
    napi_status stat = napi_get_value_string_utf8(env, value, nullptr, 0, &valueLen);
    if (stat != napi_ok) {
        return false;
    }
    if (!CheckArgsVal(env, valueLen > 0, valueName, "len == 0")) {
        return false;
    }
    if (!CheckArgsVal(env, valueLen < DM_NAPI_BUF_LENGTH, valueName, "len >= MAXLEN")) {
        return false;
    }
    char temp[DM_NAPI_BUF_LENGTH] = {0};
    napi_status status = napi_get_value_string_utf8(env, value, temp, valueLen + 1, &valueLen);
    if (status != napi_ok) {
        return false;
    }
    strValue = temp;
    return true;
}

void JsObjectToStrVector(const napi_env &env, const napi_value &object, const std::string &fieldStr,
    std::vector<std::string> &fieldRef)
{
    bool hasProperty = false;
    NAPI_CALL_RETURN_VOID(env, napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty));
    if (!hasProperty) {
        LOGE("no property: %{public}s", fieldStr.c_str());
        return;
    }

    napi_value field = nullptr;
    napi_get_named_property(env, object, fieldStr.c_str(), &field);
    bool isArr = false;
    napi_is_array(env, field, &isArr);
    if (!isArr) {
        LOGE("property: %{public}s is not array", fieldStr.c_str());
        return;
    }
    uint32_t length = 0;
    napi_get_array_length(env, field, &length);
    for (size_t i = 0; i < length; i++) {
        napi_value element;
        napi_get_element(env, field, i, &element);
        size_t strLen = 0;
        napi_get_value_string_utf8(env, element, nullptr, 0, &strLen);
        if (strLen == 0) {
            continue;
        }
        char buf[DEVICE_UUID_LENGTH] = {0};
        napi_get_value_string_utf8(env, element, buf, strLen + 1, &strLen);
        fieldRef.emplace_back(buf);
    }
}

void JsObjectToStrVector(const napi_env &env, const napi_value &object, std::vector<std::string> &fieldRef)
{
    bool isArr = false;
    napi_is_array(env, object, &isArr);
    if (!isArr) {
        LOGE("object is not array");
        return;
    }
    uint32_t length = 0;
    napi_get_array_length(env, object, &length);
    for (size_t i = 0; i < length; i++) {
        napi_value element;
        NAPI_CALL_RETURN_VOID(env, napi_get_element(env, object, i, &element));
        size_t strLen = 0;
        napi_get_value_string_utf8(env, element, nullptr, 0, &strLen);
        if (strLen == 0 || strLen >= DM_MAX_DEVICE_ID_LEN) {
            continue;
        }
        char buf[DM_MAX_DEVICE_ID_LEN] = {0};
        napi_get_value_string_utf8(env, element, buf, strLen + 1, &strLen);
        fieldRef.emplace_back(buf);
    }
}

void JsToDmDeviceProfileInfoFilterOptions(const napi_env &env, const napi_value &object,
    DmDeviceProfileInfoFilterOptions &info)
{
    napi_valuetype filterOptionsType;
    napi_typeof(env, object, &filterOptionsType);
    if (filterOptionsType != napi_object) {
        LOGE("filterOptions is not object");
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + " The type of filterOptions must be object";
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
        return;
    }
    bool isCloud = false;
    JsObjectToBool(env, object, "isCloud", isCloud);
    info.isCloud = isCloud;
    std::vector<std::string> deviceIdList;
    JsObjectToStrVector(env, object, "deviceIdList", deviceIdList);
    info.deviceIdList = deviceIdList;
}

void JsToDmDeviceNetworkIdFilterOptions(const napi_env &env, const napi_value &object,
    NetworkIdQueryFilter &info)
{
    napi_valuetype filterOptionsType;
    napi_typeof(env, object, &filterOptionsType);
    if (filterOptionsType != napi_object) {
        LOGE("filterOptions is not object");
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + " The type of filterOptions must be object";
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
        return;
    }
    char wiseDeviceId[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "wiseDeviceId", wiseDeviceId, sizeof(wiseDeviceId));
    info.wiseDeviceId = wiseDeviceId;
    int32_t onlineStatus = 0;
    JsObjectToInt(env, object, "onlineStatus", onlineStatus);
    info.onlineStatus = onlineStatus;
}

void DmServiceProfileInfoToJsArray(const napi_env &env, const std::vector<DmServiceProfileInfo> &svrInfos,
    napi_value &arrayResult)
{
    for (uint32_t i = 0; i < svrInfos.size(); i++) {
        napi_value item = nullptr;
        napi_create_object(env, &item);
        SetValueUtf8String(env, "deviceId", svrInfos[i].deviceId, item);
        SetValueUtf8String(env, "serviceId", svrInfos[i].serviceId, item);
        SetValueUtf8String(env, "serviceType", svrInfos[i].serviceType, item);
        JsonObject jsonObj;
        for (const auto& [key, value] : svrInfos[i].data) {
            jsonObj[key] = value;
        }
        SetValueUtf8String(env, "data", jsonObj.Dump(), item);
        napi_status status = napi_set_element(env, arrayResult, i, item);
        if (status != napi_ok) {
            LOGE("To JsArray set element error: %{public}d", status);
        }
    }
}

void DmDeviceProfileInfoToJs(const napi_env &env, const DmDeviceProfileInfo &devInfo, napi_value &jsObj)
{
    SetValueUtf8String(env, "deviceId", devInfo.deviceId, jsObj);
    SetValueUtf8String(env, "deviceSn", devInfo.deviceSn, jsObj);
    SetValueUtf8String(env, "mac", devInfo.mac, jsObj);
    SetValueUtf8String(env, "model", devInfo.model, jsObj);
    SetValueUtf8String(env, "internalModel", devInfo.internalModel, jsObj);
    SetValueUtf8String(env, "deviceType", devInfo.deviceType, jsObj);
    SetValueUtf8String(env, "manufacturer", devInfo.manufacturer, jsObj);
    SetValueUtf8String(env, "deviceName", devInfo.deviceName, jsObj);
    SetValueUtf8String(env, "productName", devInfo.productName, jsObj);
    SetValueUtf8String(env, "productId", devInfo.productId, jsObj);
    SetValueUtf8String(env, "subProductId", devInfo.subProductId, jsObj);
    SetValueUtf8String(env, "sdkVersion", devInfo.sdkVersion, jsObj);
    SetValueUtf8String(env, "bleMac", devInfo.bleMac, jsObj);
    SetValueUtf8String(env, "brMac", devInfo.brMac, jsObj);
    SetValueUtf8String(env, "sleMac", devInfo.sleMac, jsObj);
    SetValueUtf8String(env, "firmwareVersion", devInfo.firmwareVersion, jsObj);
    SetValueUtf8String(env, "hardwareVersion", devInfo.hardwareVersion, jsObj);
    SetValueUtf8String(env, "softwareVersion", devInfo.softwareVersion, jsObj);
    SetValueInt32(env, "protocolType", devInfo.protocolType, jsObj);
    SetValueInt32(env, "setupType", devInfo.setupType, jsObj);
    SetValueUtf8String(env, "wiseDeviceId", devInfo.wiseDeviceId, jsObj);
    SetValueUtf8String(env, "wiseUserId", devInfo.wiseUserId, jsObj);
    SetValueUtf8String(env, "registerTime", devInfo.registerTime, jsObj);
    SetValueUtf8String(env, "modifyTime", devInfo.modifyTime, jsObj);
    SetValueUtf8String(env, "shareTime", devInfo.shareTime, jsObj);
    SetValueInt32(env, "isLocalDevice", devInfo.isLocalDevice ? 1 : 0, jsObj);
}

void DmDeviceProfileInfoToJsArray(const napi_env &env, const std::vector<DmDeviceProfileInfo> &devInfos,
    napi_value &arrayResult)
{
    for (uint32_t i = 0; i < devInfos.size(); i++) {
        napi_value item = nullptr;
        napi_create_object(env, &item);
        DmDeviceProfileInfoToJs(env, devInfos[i], item);
        if (!devInfos[i].services.empty()) {
            napi_value services = nullptr;
            napi_create_array(env, &services);
            bool isArray = false;
            napi_is_array(env, services, &isArray);
            if (!isArray) {
                LOGE("napi_create_array failed");
            }
            DmServiceProfileInfoToJsArray(env, devInfos[i].services, services);
            napi_set_named_property(env, item, "services", services);
        }
        napi_status status = napi_set_element(env, arrayResult, i, item);
        if (status != napi_ok) {
            LOGE("DmDeviceProfileInfo To JsArray set element error: %{public}d", status);
        }
    }
}

void JsToDmDeviceIconInfoFilterOptions(const napi_env &env, const napi_value &object,
    DmDeviceIconInfoFilterOptions &info)
{
    napi_valuetype filterOptionsType;
    napi_typeof(env, object, &filterOptionsType);
    if (filterOptionsType != napi_object) {
        LOGE("filterOptions is not object");
        std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + " The type of filterOptions must be object";
        napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
        return;
    }
    char productId[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "productId", productId, sizeof(productId));
    info.productId = productId;
    char subProductId[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "subProductId", subProductId, sizeof(subProductId));
    info.subProductId = subProductId;
    char internalModel[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "internalModel", internalModel, sizeof(internalModel));
    info.internalModel = internalModel;
    char imageType[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "imageType", imageType, sizeof(imageType));
    info.imageType = imageType;
    char specName[DM_NAPI_BUF_LENGTH] = "";
    JsObjectToString(env, object, "specName", specName, sizeof(specName));
    info.specName = specName;
}

void DmDeviceIconInfoToJs(const napi_env &env, const DmDeviceIconInfo &deviceIconInfo, napi_value &jsObj)
{
    SetValueUtf8String(env, "productId", deviceIconInfo.productId, jsObj);
    SetValueUtf8String(env, "internalModel", deviceIconInfo.internalModel, jsObj);
    SetValueUtf8String(env, "subProductId", deviceIconInfo.subProductId, jsObj);
    SetValueUtf8String(env, "imageType", deviceIconInfo.imageType, jsObj);
    SetValueUtf8String(env, "specName", deviceIconInfo.specName, jsObj);
    SetValueUtf8String(env, "url", deviceIconInfo.url, jsObj);
    size_t iconLen = deviceIconInfo.icon.size();
    if (iconLen > 0) {
        void *icon = nullptr;
        napi_value iconBuffer = nullptr;
        napi_create_arraybuffer(env, iconLen, &icon, &iconBuffer);
        if (icon != nullptr &&
            memcpy_s(icon, iconLen, reinterpret_cast<const void *>(deviceIconInfo.icon.data()), iconLen) == 0) {
            napi_value iconArray = nullptr;
            napi_create_typedarray(env, napi_uint8_array, iconLen, iconBuffer, 0, &iconArray);
            napi_set_named_property(env, jsObj, "icon", iconArray);
        }
    }
}

bool JsToDmServiceProfileInfo(const napi_env &env, const napi_value &jsObj, DmServiceProfileInfo &svrInfos)
{
    napi_valuetype jsObjType;
    napi_typeof(env, jsObj, &jsObjType);
    if (jsObjType != napi_object) {
        LOGE("jsObjType is not object");
        return false;
    }
    svrInfos.serviceId = GetStrFromJsObj(env, jsObj, "sid");
    svrInfos.serviceType = GetStrFromJsObj(env, jsObj, "st");
    return true;
}

std::vector<DmServiceProfileInfo> GetServiceProfileInfosFromJsObj(const napi_env &env, const napi_value &jsObj,
    const std::string &fieldStr)
{
    bool hasProperty = false;
    napi_has_named_property(env, jsObj, fieldStr.c_str(), &hasProperty);
    if (!hasProperty) {
        return {};
    }
    napi_value jsServicesArray = nullptr;
    napi_get_named_property(env, jsObj, fieldStr.c_str(), &jsServicesArray);
    bool isArr = false;
    napi_is_array(env, jsObj, &isArr);
    if (!isArr) {
        LOGE("object is not array");
        return {};
    }
    std::vector<DmServiceProfileInfo> services = {};
    uint32_t length = 0;
    napi_get_array_length(env, jsServicesArray, &length);
    for (size_t i = 0; i < length; i++) {
        napi_value element;
        napi_get_element(env, jsServicesArray, i, &element);
        DmServiceProfileInfo svrInfo;
        if (JsToDmServiceProfileInfo(env, jsServicesArray, svrInfo)) {
            services.emplace_back(svrInfo);
        }
    }
    return services;
}

bool JsToDmDeviceProfileInfo(const napi_env &env, const napi_value &jsObj, DmDeviceProfileInfo &devInfo)
{
    napi_valuetype jsObjType;
    napi_typeof(env, jsObj, &jsObjType);
    if (jsObjType != napi_object) {
        LOGE("jsObjType is not object");
        return false;
    }
    devInfo.deviceId = GetStrFromJsObj(env, jsObj, "deviceId");
    devInfo.deviceSn = GetStrFromJsObj(env, jsObj, "deviceSn");
    devInfo.mac = GetStrFromJsObj(env, jsObj, "mac");
    devInfo.model = GetStrFromJsObj(env, jsObj, "model");
    devInfo.internalModel = GetStrFromJsObj(env, jsObj, "internalModel");
    devInfo.deviceType = GetStrFromJsObj(env, jsObj, "deviceType");
    devInfo.manufacturer = GetStrFromJsObj(env, jsObj, "manufacturer");
    devInfo.deviceName = GetStrFromJsObj(env, jsObj, "deviceName");
    devInfo.productName = GetStrFromJsObj(env, jsObj, "productName");
    devInfo.productId = GetStrFromJsObj(env, jsObj, "productId");
    devInfo.subProductId = GetStrFromJsObj(env, jsObj, "subProductId");
    devInfo.sdkVersion = GetStrFromJsObj(env, jsObj, "sdkVersion");
    devInfo.bleMac = GetStrFromJsObj(env, jsObj, "bleMac");
    devInfo.brMac = GetStrFromJsObj(env, jsObj, "brMac");
    devInfo.sleMac = GetStrFromJsObj(env, jsObj, "sleMac");
    devInfo.firmwareVersion = GetStrFromJsObj(env, jsObj, "firmwareVersion");
    devInfo.hardwareVersion = GetStrFromJsObj(env, jsObj, "hardwareVersion");
    devInfo.softwareVersion = GetStrFromJsObj(env, jsObj, "softwareVersion");
    devInfo.protocolType = GetIntFromJsObj(env, jsObj, "protocolType");
    devInfo.setupType = GetIntFromJsObj(env, jsObj, "setupType");
    devInfo.wiseDeviceId = GetStrFromJsObj(env, jsObj, "wiseDeviceId");
    devInfo.registerTime = GetStrFromJsObj(env, jsObj, "registerTime");
    devInfo.modifyTime = GetStrFromJsObj(env, jsObj, "modifyTime");
    devInfo.shareTime = GetStrFromJsObj(env, jsObj, "shareTime");
    devInfo.services = GetServiceProfileInfosFromJsObj(env, jsObj, "services");
    for (auto &item : devInfo.services) {
        item.deviceId = devInfo.deviceId;
    }
    return true;
}

bool JsToDmDeviceProfileInfos(const napi_env &env, const napi_value &jsObj, std::vector<DmDeviceProfileInfo> &devInfos)
{
    bool isArr = false;
    napi_is_array(env, jsObj, &isArr);
    if (!isArr) {
        LOGE("object is not array");
        return false;
    }
    uint32_t length = 0;
    napi_get_array_length(env, jsObj, &length);
    for (size_t i = 0; i < length; i++) {
        napi_value element;
        napi_get_element(env, jsObj, i, &element);
        DmDeviceProfileInfo devInfo;
        if (JsToDmDeviceProfileInfo(env, element, devInfo)) {
            devInfos.emplace_back(devInfo);
        }
    }
    return true;
}
} // namespace DistributedHardware
} // namespace OHOS