/*
 * Copyright (C) 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.
 */
#define MLOG_TAG "RingtoneScanner"

#include "ringtone_scanner_db.h"

#include "result_set_utils.h"
#include "rdb_errno.h"
#include "rdb_utils.h"
#include "ringtone_errno.h"
#include "ringtone_file_utils.h"
#include "ringtone_log.h"
#include "ringtone_rdbstore.h"

namespace OHOS {
namespace Media {
using namespace std;
using namespace OHOS::NativeRdb;
using namespace OHOS::DataShare;
int32_t RingtoneScannerDb::GetFileBasicInfo(const string &path, unique_ptr<RingtoneMetadata> &ptr)
{
    vector<string> columns = {};
    string whereClause = RINGTONE_COLUMN_DATA + " = ?";
    vector<string> args = { path };

    Uri uri("");
    RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::QUERY);
    cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
    cmd.GetAbsRdbPredicates()->SetWhereArgs(args);

    shared_ptr<NativeRdb::ResultSet> resultSet;
    int32_t ret = GetFileSet(cmd, columns, resultSet);
    if (ret != E_OK) {
        RINGTONE_ERR_LOG("Update operation failed. ret=%{public}d", ret);
        return E_DB_FAIL;
    }

    return FillMetadata(resultSet, ptr);
}

int32_t RingtoneScannerDb::GetVibrateFileBasicInfo(const string &path, unique_ptr<VibrateMetadata> &ptr)
{
    vector<string> columns = {
        VIBRATE_COLUMN_VIBRATE_ID, VIBRATE_COLUMN_SIZE, VIBRATE_COLUMN_DATE_MODIFIED, VIBRATE_COLUMN_TITLE,
        VIBRATE_COLUMN_DATE_ADDED
    };
    string whereClause = VIBRATE_COLUMN_DATA + " = ?";
    vector<string> args = { path };

    Uri uri("");
    RingtoneDataCommand cmd(uri, VIBRATE_TABLE, RingtoneOperationType::QUERY);
    cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
    cmd.GetAbsRdbPredicates()->SetWhereArgs(args);

    shared_ptr<NativeRdb::ResultSet> resultSet;
    int32_t ret = GetFileSet(cmd, columns, resultSet);
    if (ret != E_OK) {
        RINGTONE_ERR_LOG("Update operation failed. ret=%{public}d", ret);
        return E_DB_FAIL;
    }

    return FillVibrateMetadata(resultSet, ptr);
}

int32_t RingtoneScannerDb::GetRingMockHapticAudioFileBasicInfo(const string &path,
    unique_ptr<RingMockHapticAudioMetadata> &ptr)
{
    vector<string> columns = {
        HAPTIC_2_TONE_COLUMN_ID, HAPTIC_2_TONE_COLUMN_SIZE, HAPTIC_2_TONE_COLUMN_DATE_MODIFIED,
        HAPTIC_2_TONE_COLUMN_TITLE, HAPTIC_2_TONE_COLUMN_DATE_ADDED
    };
    string whereClause = HAPTIC_2_TONE_COLUMN_DATA + " = ?";
    vector<string> args = { path };

    Uri uri("");
    RingtoneDataCommand cmd(uri, HAPTIC_2_TONE_TABLE, RingtoneOperationType::QUERY);
    cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
    cmd.GetAbsRdbPredicates()->SetWhereArgs(args);

    shared_ptr<NativeRdb::ResultSet> resultSet;
    int32_t ret = GetFileSet(cmd, columns, resultSet);
    if (ret != E_OK) {
        RINGTONE_ERR_LOG("Query operation failed. ret=%{public}d", ret);
        return E_DB_FAIL;
    }

    return FillRingMockHapticAudioMetadata(resultSet, ptr);
}

int32_t RingtoneScannerDb::QueryRingtoneRdb(const string &whereClause, vector<string> &whereArgs,
    const vector<string> &columns, shared_ptr<NativeRdb::ResultSet> &resultSet, const string &tableName)
{
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb store");
        return E_RDB;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return E_RDB;
    }

    AbsRdbPredicates absRdbPredicates(tableName);
    absRdbPredicates.SetWhereClause(whereClause);
    absRdbPredicates.SetWhereArgs(whereArgs);
    resultSet = rawRdb->Query(absRdbPredicates, columns);
    if (resultSet == nullptr) {
        RINGTONE_ERR_LOG("return nullptr when query rdb");
        return E_RDB;
    }

    return E_OK;
}

int32_t RingtoneScannerDb::UpdateRingtoneRdb(ValuesBucket &values, const string &whereClause,
    vector<string> &whereArgs, const string &tableName)
{
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return E_RDB;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return E_RDB;
    }
    int32_t updateCount = 0;
    int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
    if (result != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
        return E_DB_FAIL;
    }
    return updateCount;
}

int32_t RingtoneScannerDb::FillMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
    unique_ptr<RingtoneMetadata> &ptr)
{
    std::vector<std::string> columnNames;
    int32_t err = resultSet->GetAllColumnNames(columnNames);
    if (err != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("failed to get all column names");
        return E_RDB;
    }

    for (const auto &col : columnNames) {
        ExtractMetaFromColumn(resultSet, ptr, col);
    }

    return E_OK;
}

int32_t RingtoneScannerDb::FillVibrateMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
    unique_ptr<VibrateMetadata> &ptr)
{
    std::vector<std::string> columnNames;
    int32_t err = resultSet->GetAllColumnNames(columnNames);
    if (err != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("failed to get all column names");
        return E_RDB;
    }

    for (const auto &col : columnNames) {
        ExtractVibrateMetaFromColumn(resultSet, ptr, col);
    }

    return E_OK;
}

int32_t RingtoneScannerDb::FillRingMockHapticAudioMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
    unique_ptr<RingMockHapticAudioMetadata> &ptr)
{
    std::vector<std::string> columnNames;
    int32_t err = resultSet->GetAllColumnNames(columnNames);
    if (err != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("failed to get all column names");
        return E_RDB;
    }

    for (const auto &col : columnNames) {
        ExtractRingMockHapticAudioMetaFromColumn(resultSet, ptr, col);
    }

    return E_OK;
}

void RingtoneScannerDb::ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
    unique_ptr<RingtoneMetadata> &metadata, const std::string &col)
{
    RingtoneResultSetDataType dataType = RingtoneResultSetDataType::DATA_TYPE_NULL;
    RingtoneMetadata::RingtoneMetadataFnPtr requestFunc = nullptr;
    auto itr = metadata->memberFuncMap_.find(col);
    if (itr != metadata->memberFuncMap_.end()) {
        dataType = itr->second.first;
        requestFunc = itr->second.second;
    } else {
        RINGTONE_DEBUG_LOG("invalid column name %{public}s", col.c_str());
        return;
    }

    std::variant<int32_t, std::string, int64_t, double> data =
        ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);

    // Use the function pointer from map and pass data to fn ptr
    if (requestFunc != nullptr) {
        (metadata.get()->*requestFunc)(data);
    }
}

void RingtoneScannerDb::ExtractVibrateMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
    unique_ptr<VibrateMetadata> &metadata, const std::string &col)
{
    RingtoneResultSetDataType dataType = RingtoneResultSetDataType::DATA_TYPE_NULL;
    VibrateMetadata::VibrateMetadataFnPtr requestFunc = nullptr;
    auto itr = metadata->memberFuncMap_.find(col);
    if (itr != metadata->memberFuncMap_.end()) {
        dataType = itr->second.first;
        requestFunc = itr->second.second;
    } else {
        RINGTONE_DEBUG_LOG("invalid column name %{public}s", col.c_str());
        return;
    }

    std::variant<int32_t, std::string, int64_t, double> data =
        ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);

    // Use the function pointer from map and pass data to fn ptr
    if (requestFunc != nullptr) {
        (metadata.get()->*requestFunc)(data);
    }
}

void RingtoneScannerDb::ExtractRingMockHapticAudioMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
    unique_ptr<RingMockHapticAudioMetadata> &metadata, const std::string &col)
{
    RingtoneResultSetDataType dataType = RingtoneResultSetDataType::DATA_TYPE_NULL;
    RingMockHapticAudioMetadata::RingMockHapticAudioMetadataFnPtr requestFunc = nullptr;
    auto itr = metadata->memberFuncMap_.find(col);
    if (itr != metadata->memberFuncMap_.end()) {
        dataType = itr->second.first;
        requestFunc = itr->second.second;
    } else {
        RINGTONE_DEBUG_LOG("invalid column name %{public}s", col.c_str());
        return;
    }

    std::variant<int32_t, std::string, int64_t, double> data =
        ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);

    if (requestFunc != nullptr) {
        (metadata.get()->*requestFunc)(data);
    }
}

int32_t RingtoneScannerDb::GetFileSet(RingtoneDataCommand &cmd, const vector<string> &columns,
    shared_ptr<NativeRdb::ResultSet> &resultSet)
{
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return E_RDB;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return E_RDB;
    }
    resultSet = rawRdb->Query(*cmd.GetAbsRdbPredicates(), columns);
    if (resultSet == nullptr) {
        RINGTONE_ERR_LOG("return nullptr when query rdb");
        return E_RDB;
    }

    int32_t rowCount = 0;
    int32_t ret = resultSet->GetRowCount(rowCount);
    if (ret != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("failed to get row count");
        return E_RDB;
    }
    if (rowCount == 0) {
        return E_OK;
    }

    ret = resultSet->GoToFirstRow();
    if (ret != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("failed to go to first row");
        return E_RDB;
    }
    return E_OK;
}

static void InsertDateAdded(const RingtoneMetadata &metadata, ValuesBucket &outValues)
{
    int64_t dateAdded = metadata.GetDateAdded();
    if (dateAdded == 0) {
        int64_t dateTaken = metadata.GetDateTaken();
        if (dateTaken == 0) {
            int64_t dateModified = metadata.GetDateModified();
            if (dateModified == 0) {
                dateAdded = RingtoneFileUtils::UTCTimeMilliSeconds();
                RINGTONE_WARN_LOG("Invalid dateAdded time, use current time instead: %{public}" PRId64, dateAdded);
            } else {
                dateAdded = dateModified;
                RINGTONE_WARN_LOG("Invalid dateAdded time, use dateModified instead: %{public}" PRId64, dateAdded);
            }
        } else {
            dateAdded = dateTaken * MSEC_TO_SEC;
            RINGTONE_WARN_LOG("Invalid dateAdded time, use dateTaken instead: %{public}" PRId64, dateAdded);
        }
    }
    outValues.PutLong(RINGTONE_COLUMN_DATE_ADDED, dateAdded);
}

static void InsertVibrateDateAdded(const VibrateMetadata &metadata, ValuesBucket &outValues)
{
    int64_t dateAdded = metadata.GetDateAdded();
    if (dateAdded == 0) {
        int64_t dateTaken = metadata.GetDateTaken();
        if (dateTaken == 0) {
            int64_t dateModified = metadata.GetDateModified();
            if (dateModified == 0) {
                dateAdded = RingtoneFileUtils::UTCTimeMilliSeconds();
                RINGTONE_WARN_LOG("Invalid dateAdded time, use current time instead: %{public}" PRId64, dateAdded);
            } else {
                dateAdded = dateModified;
                RINGTONE_WARN_LOG("Invalid dateAdded time, use dateModified instead: %{public}" PRId64, dateAdded);
            }
        } else {
            dateAdded = dateTaken * MSEC_TO_SEC;
            RINGTONE_WARN_LOG("Invalid dateAdded time, use dateTaken instead: %{public}" PRId64, dateAdded);
        }
    }
    outValues.PutLong(VIBRATE_COLUMN_DATE_ADDED, dateAdded);
}

static void SetValuesFromMetaData(const RingtoneMetadata &metadata, ValuesBucket &values, bool isInsert)
{
    values.PutString(RINGTONE_COLUMN_DATA, metadata.GetData());
    values.PutLong(RINGTONE_COLUMN_SIZE, metadata.GetSize());
    values.PutString(RINGTONE_COLUMN_DISPLAY_NAME, metadata.GetDisplayName());
    values.PutString(RINGTONE_COLUMN_TITLE, metadata.GetTitle());
    values.PutInt(RINGTONE_COLUMN_MEDIA_TYPE, metadata.GetMediaType());
    values.PutInt(RINGTONE_COLUMN_TONE_TYPE, metadata.GetToneType());
    values.PutString(RINGTONE_COLUMN_MIME_TYPE, metadata.GetMimeType());
    values.PutInt(RINGTONE_COLUMN_SOURCE_TYPE, metadata.GetSourceType());
    values.PutLong(RINGTONE_COLUMN_DATE_MODIFIED, metadata.GetDateModified());
    values.PutLong(RINGTONE_COLUMN_DATE_TAKEN, metadata.GetDateTaken());
    values.PutInt(RINGTONE_COLUMN_DURATION, metadata.GetDuration());
    values.PutInt(RINGTONE_COLUMN_SHOT_TONE_TYPE, metadata.GetShotToneType());
    values.PutInt(RINGTONE_COLUMN_SHOT_TONE_SOURCE_TYPE, metadata.GetShotToneSourceType());
    values.PutInt(RINGTONE_COLUMN_NOTIFICATION_TONE_TYPE, metadata.GetNotificationToneType());
    values.PutInt(RINGTONE_COLUMN_NOTIFICATION_TONE_SOURCE_TYPE, metadata.GetNotificationToneSourceType());
    values.PutInt(RINGTONE_COLUMN_RING_TONE_TYPE, metadata.GetRingToneType());
    values.PutInt(RINGTONE_COLUMN_RING_TONE_SOURCE_TYPE, metadata.GetRingToneSourceType());
    values.PutInt(RINGTONE_COLUMN_ALARM_TONE_TYPE, metadata.GetAlarmToneType());
    values.PutInt(RINGTONE_COLUMN_ALARM_TONE_SOURCE_TYPE, metadata.GetAlarmToneSourceType());
    values.PutInt(RINGTONE_COLUMN_SCANNER_FLAG, 1);

    if (isInsert) {
        InsertDateAdded(metadata, values);
        return;
    }
}

static void SetValuesFromVibrateMetaData(const VibrateMetadata &metadata, ValuesBucket &values, bool isInsert)
{
    values.PutString(VIBRATE_COLUMN_DATA, metadata.GetData());
    values.PutLong(VIBRATE_COLUMN_SIZE, metadata.GetSize());
    values.PutString(VIBRATE_COLUMN_DISPLAY_NAME, metadata.GetDisplayName());
    values.PutString(VIBRATE_COLUMN_TITLE, metadata.GetTitle());
    values.PutString(VIBRATE_COLUMN_DISPLAY_LANGUAGE, metadata.GetDisplayLanguage());
    values.PutInt(VIBRATE_COLUMN_VIBRATE_TYPE, metadata.GetVibrateType());
    values.PutInt(VIBRATE_COLUMN_SOURCE_TYPE, metadata.GetSourceType());
    values.PutLong(VIBRATE_COLUMN_DATE_MODIFIED, metadata.GetDateModified());
    values.PutLong(VIBRATE_COLUMN_DATE_TAKEN, metadata.GetDateTaken());
    values.PutInt(VIBRATE_COLUMN_PLAY_MODE, metadata.GetPlayMode());
    values.PutInt(VIBRATE_COLUMN_SCANNER_FLAG, 1);

    if (isInsert) {
        InsertVibrateDateAdded(metadata, values);
    }
}

int32_t RingtoneScannerDb::UpdateMetadata(const RingtoneMetadata &metadata, string &tableName)
{
    int32_t updateCount = 0;
    ValuesBucket values;
    string whereClause = RINGTONE_COLUMN_TONE_ID + " = ?";
    vector<string> whereArgs = { to_string(metadata.GetToneId()) };

    SetValuesFromMetaData(metadata, values, false);

    tableName = RINGTONE_TABLE;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return E_RDB;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return E_RDB;
    }
    RINGTONE_DEBUG_LOG("Update operation. tableName %{public}s. whereClause %{public}s", tableName.c_str(),
        whereClause.c_str());
    int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
    if (result != NativeRdb::E_OK || updateCount <= 0) {
        RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
        return E_DB_FAIL;
    }
    return updateCount;
}

int32_t RingtoneScannerDb::UpdateVibrateMetadata(const VibrateMetadata &metadata, string &tableName)
{
    int32_t updateCount = 0;
    ValuesBucket values;
    string whereClause = VIBRATE_COLUMN_VIBRATE_ID + " = ?";
    vector<string> whereArgs = { to_string(metadata.GetVibrateId()) };

    SetValuesFromVibrateMetaData(metadata, values, false);

    tableName = VIBRATE_TABLE;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return E_RDB;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return E_RDB;
    }
    int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
    if (result != NativeRdb::E_OK || updateCount <= 0) {
        RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
        return E_DB_FAIL;
    }
    return updateCount;
}

int32_t RingtoneScannerDb::InsertMetadata(const RingtoneMetadata &metadata, string &tableName)
{
    ValuesBucket values;
    int32_t rowNum = 0;
    tableName = RINGTONE_TABLE;

    SetValuesFromMetaData(metadata, values, true);
    if (!InsertData(values, tableName, rowNum)) {
        return E_DB_FAIL;
    }

    return rowNum;
}

int32_t RingtoneScannerDb::InsertVibrateMetadata(const VibrateMetadata &metadata, string &tableName)
{
    ValuesBucket values;
    int32_t rowNum = 0;
    tableName = VIBRATE_TABLE;

    SetValuesFromVibrateMetaData(metadata, values, true);
    if (!InsertData(values, tableName, rowNum)) {
        return E_DB_FAIL;
    }

    return rowNum;
}

int32_t RingtoneScannerDb::InsertRingMockHapticAudioMetadata(const RingMockHapticAudioMetadata &metadata,
    string &tableName)
{
    ValuesBucket values;
    int32_t rowNum = 0;
    tableName = HAPTIC_2_TONE_TABLE;

    values.PutString(HAPTIC_2_TONE_COLUMN_DATA, metadata.GetData());
    values.PutLong(HAPTIC_2_TONE_COLUMN_SIZE, metadata.GetSize());
    values.PutString(HAPTIC_2_TONE_COLUMN_DISPLAY_NAME, metadata.GetDisplayName());
    values.PutString(HAPTIC_2_TONE_COLUMN_TITLE, metadata.GetTitle());
    values.PutInt(HAPTIC_2_TONE_COLUMN_HAPTIC_2_TONE_TYPE, metadata.GetRingMockHapticAudioType());
    values.PutInt(HAPTIC_2_TONE_COLUMN_SOURCE_TYPE, metadata.GetSourceType());
    values.PutLong(HAPTIC_2_TONE_COLUMN_DATE_ADDED, metadata.GetDateAdded());
    values.PutLong(HAPTIC_2_TONE_COLUMN_DATE_MODIFIED, metadata.GetDateModified());
    values.PutInt(HAPTIC_2_TONE_COLUMN_PLAY_MODE, metadata.GetPlayMode());
    values.PutInt(HAPTIC_2_TONE_COLUMN_SCANNER_FLAG, metadata.GetScannerFlag());

    if (!InsertData(values, tableName, rowNum)) {
        return E_DB_FAIL;
    }

    return rowNum;
}

bool RingtoneScannerDb::InsertData(const ValuesBucket values, const string &tableName, int32_t &rowNum)
{
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return false;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return false;
    }

    int64_t nRow = static_cast<int64_t>(rowNum);
    int32_t result = rawRdb->Insert(nRow, tableName, values);
    if (nRow <= 0) {
        RINGTONE_ERR_LOG("Ringtone library Insert functionality is failed, rowNum %{public}ld", (long) nRow);
        return false;
    }

    if (result != NativeRdb::E_OK) {
        RINGTONE_ERR_LOG("Ringtone library Insert functionality is failed, return %{public}d", result);
        return false;
    }

    if (nRow < std::numeric_limits<int32_t>::min() || nRow > std::numeric_limits<int32_t>::max()) {
        return false;
    }
    rowNum = static_cast<int32_t>(nRow);

    return true;
}

int32_t RingtoneScannerDb::UpdateRingMockHapticAudioMetadata(const RingMockHapticAudioMetadata &metadata,
    string &tableName)
{
    int32_t updateCount = 0;
    ValuesBucket values;
    string whereClause = HAPTIC_2_TONE_COLUMN_ID + " = ?";
    vector<string> whereArgs = { to_string(metadata.GetId()) };

    values.PutString(HAPTIC_2_TONE_COLUMN_DATA, metadata.GetData());
    values.PutLong(HAPTIC_2_TONE_COLUMN_SIZE, metadata.GetSize());
    values.PutString(HAPTIC_2_TONE_COLUMN_DISPLAY_NAME, metadata.GetDisplayName());
    values.PutString(HAPTIC_2_TONE_COLUMN_TITLE, metadata.GetTitle());
    values.PutInt(HAPTIC_2_TONE_COLUMN_HAPTIC_2_TONE_TYPE, metadata.GetRingMockHapticAudioType());
    values.PutInt(HAPTIC_2_TONE_COLUMN_SOURCE_TYPE, metadata.GetSourceType());
    values.PutLong(HAPTIC_2_TONE_COLUMN_DATE_ADDED, metadata.GetDateAdded());
    values.PutLong(HAPTIC_2_TONE_COLUMN_DATE_MODIFIED, metadata.GetDateModified());
    values.PutInt(HAPTIC_2_TONE_COLUMN_PLAY_MODE, metadata.GetPlayMode());
    values.PutInt(HAPTIC_2_TONE_COLUMN_SCANNER_FLAG, metadata.GetScannerFlag());

    tableName = HAPTIC_2_TONE_TABLE;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return E_RDB;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return E_RDB;
    }
    int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
    if (result != NativeRdb::E_OK || updateCount <= 0) {
        RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
        return E_DB_FAIL;
    }
    return updateCount;
}

bool RingtoneScannerDb::UpdateScannerFlag()
{
    int32_t updateCount = 0;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return false;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return false;
    }

    ValuesBucket ringtoneValues;
    DataShare::DataSharePredicates ringtonePredicates;
    int32_t result;
    NativeRdb::RdbPredicates ringtoneRdbPredicate = RdbDataShareAdapter::RdbUtils::ToPredicates(ringtonePredicates,
        RINGTONE_TABLE);
    ringtoneValues.PutInt(RINGTONE_COLUMN_SCANNER_FLAG, 0);
    result = rawRdb->Update(updateCount, ringtoneValues, ringtoneRdbPredicate);
    RINGTONE_INFO_LOG("Ringtone update operation end. Updated %{public}d", updateCount);
    if (result != NativeRdb::E_OK || updateCount < 0) {
        RINGTONE_ERR_LOG("Ringtone update operation failed. Result %{public}d. Updated %{public}d",
            result, updateCount);
        return false;
    }

    ValuesBucket vibrateValues;
    DataShare::DataSharePredicates vibratePredicates;
    NativeRdb::RdbPredicates vibrateRdbPredicate = RdbDataShareAdapter::RdbUtils::ToPredicates(vibratePredicates,
        VIBRATE_TABLE);
    vibrateValues.PutInt(VIBRATE_COLUMN_SCANNER_FLAG, 0);
    result = rawRdb->Update(updateCount, vibrateValues, vibrateRdbPredicate);
    RINGTONE_INFO_LOG("Vibrate update operation end. Updated %{public}d", updateCount);
    if (result != NativeRdb::E_OK || updateCount < 0) {
        RINGTONE_ERR_LOG("Vibrate update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
        return false;
    }
    return true;
}

bool RingtoneScannerDb::DeleteNotExist()
{
    int32_t deleteCount = 0;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return false;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return false;
    }

    DataShare::DataSharePredicates ringtonePredicates;
    int32_t result;
    NativeRdb::RdbPredicates ringtoneRdbPredicate = RdbDataShareAdapter::RdbUtils::ToPredicates(ringtonePredicates,
        RINGTONE_TABLE);
    ringtoneRdbPredicate.EqualTo(RINGTONE_COLUMN_SCANNER_FLAG, "0");
    ringtoneRdbPredicate.And();
    ringtoneRdbPredicate.EqualTo(RINGTONE_COLUMN_SOURCE_TYPE, "1");
    result = rawRdb->Delete(deleteCount, ringtoneRdbPredicate);
    RINGTONE_WARN_LOG("Ringtone delete operation end. Deleted %{public}d", deleteCount);
    if (result != NativeRdb::E_OK || deleteCount < 0) {
        RINGTONE_ERR_LOG("Ringtone delete operation failed. Result %{public}d. Deleted %{public}d",
            result, deleteCount);
        return false;
    }

    DataShare::DataSharePredicates vibratePredicates;
    NativeRdb::RdbPredicates vibrateRdbPredicate = RdbDataShareAdapter::RdbUtils::ToPredicates(vibratePredicates,
        VIBRATE_TABLE);
    vibrateRdbPredicate.EqualTo(VIBRATE_COLUMN_SCANNER_FLAG, "0");
    vibrateRdbPredicate.And();
    vibrateRdbPredicate.EqualTo(VIBRATE_COLUMN_SOURCE_TYPE, "1");
    result = rawRdb->Delete(deleteCount, vibrateRdbPredicate);
    RINGTONE_WARN_LOG("Vibrate delete operation end. Deleted %{public}d", deleteCount);
    if (result != NativeRdb::E_OK || deleteCount < 0) {
        RINGTONE_ERR_LOG("Vibrate delete operation failed. Result %{public}d. Deleted %{public}d", result, deleteCount);
        return false;
    }
    return true;
}

bool RingtoneScannerDb::UpdateRingMockHapticAudioScannerFlag()
{
    int32_t updateCount = 0;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return false;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return false;
    }

    ValuesBucket ringMockHapticAudioValues;
    DataShare::DataSharePredicates ringMockHapticAudioPredicates;
    int32_t result;
    NativeRdb::RdbPredicates ringMockHapticAudioRdbPredicate = RdbDataShareAdapter::RdbUtils::ToPredicates(
        ringMockHapticAudioPredicates, HAPTIC_2_TONE_TABLE);
    ringMockHapticAudioValues.PutInt(HAPTIC_2_TONE_COLUMN_SCANNER_FLAG, 0);
    result = rawRdb->Update(updateCount, ringMockHapticAudioValues, ringMockHapticAudioRdbPredicate);
    RINGTONE_INFO_LOG("SimRingtone update operation end. Updated %{public}d", updateCount);
    if (result != NativeRdb::E_OK || updateCount < 0) {
        RINGTONE_ERR_LOG("SimRingtone update operation failed. Result %{public}d. Updated %{public}d",
            result, updateCount);
        return false;
    }
    return true;
}

/**
 * @brief 删除数据库中文件不存在的预置触觉反馈2音记录。
 *
 * 在支持口袋振动增强功能的设备上,开机扫描末尾调用。
 * 删除条件:HAPTIC_2_TONE_TABLE表中scanner_flag=0 且 source_type=1(预置)的记录。
 *
 * 【数据丢失风险-高】与DeleteNotExist()类似,设备升级后若触觉反馈音频文件不可达,
 * 其数据库记录会被永久删除,不可恢复。
 *
 * @return true表示删除操作成功,false表示RDB操作失败。
 */
bool RingtoneScannerDb::DeleteNotExistRingMockHapticAudio()
{
    int32_t deleteCount = 0;
    auto rdbStore = RingtoneRdbStore::GetInstance();
    if (rdbStore == nullptr) {
        RINGTONE_ERR_LOG("failed to get rdb");
        return false;
    }
    auto rawRdb = rdbStore->GetRaw();
    if (rawRdb == nullptr) {
        RINGTONE_ERR_LOG("get raw rdb failed");
        return false;
    }

    DataShare::DataSharePredicates ringMockHapticAudioPredicates;
    int32_t result;
    NativeRdb::RdbPredicates ringMockHapticAudioRdbPredicate = RdbDataShareAdapter::RdbUtils::ToPredicates(
        ringMockHapticAudioPredicates, HAPTIC_2_TONE_TABLE);
    ringMockHapticAudioRdbPredicate.EqualTo(HAPTIC_2_TONE_COLUMN_SCANNER_FLAG, "0");
    ringMockHapticAudioRdbPredicate.And();
    ringMockHapticAudioRdbPredicate.EqualTo(HAPTIC_2_TONE_COLUMN_SOURCE_TYPE, "1");
    result = rawRdb->Delete(deleteCount, ringMockHapticAudioRdbPredicate);
    RINGTONE_WARN_LOG("SimRingtone delete operation end. Deleted %{public}d", deleteCount);
    if (result != NativeRdb::E_OK || deleteCount < 0) {
        RINGTONE_ERR_LOG("SimRingtone delete operation failed. Result %{public}d. Deleted %{public}d",
            result, deleteCount);
        return false;
    }
    return true;
}
} // namespace Media
} // namespace OHOS