/*
 * Copyright (C) 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 "parameter_utils.h"

#include "permission_utils.h"
#include "medialibrary_errno.h"
#include "mimetype_utils.h"
#include "media_log.h"
#include "media_file_utils.h"
#include "media_string_utils.h"
#include "photo_album.h"
#include "userfile_manager_types.h"
#include "media_file_uri.h"
#include "medialibrary_common_utils.h"
#include "post_event_utils.h"

namespace OHOS {
namespace Media {
using namespace std;
static const int64_t MAX_INT64 = 9223372036854775807;
static const int32_t FORMID_MAX_LEN = 19;
static const int32_t EDIT_DATA_MAX_LENGTH = 5 * 1024 * 1024;
constexpr size_t MAX_TRASH_PHOTOS_SIZE = 300;
constexpr size_t MAX_DELETE_PHOTOS_COMPLETED_SIZE = 500;
constexpr int32_t USER_COMMENT_MAX_LEN = 420;
const std::unordered_set<int32_t> SUPPORTED_ORIENTATION{0, 90, 180, 270};
const int32_t MAX_PHOTO_ID_LEN = 32;

int32_t ParameterUtils::CheckFormIds(const vector<string> &formIds)
{
    if (formIds.empty()) {
        return E_ERR;
    }
    for (const auto& formId : formIds) {
        if (formId.empty() || formId.length() > FORMID_MAX_LEN) {
            return E_INVALID_ARGUMENTS;
        }
        for (uint32_t i = 0; i < formId.length(); i++) {
            if (!isdigit(formId[i])) {
                return E_INVALID_ARGUMENTS;
            }
        }
        unsigned long long num = stoull(formId);
        if (num > MAX_INT64) {
            return E_INVALID_ARGUMENTS;
        }
    }
    return E_OK;
}

bool ParameterUtils::CheckHighlightAlbum(const DeleteHighLightAlbumsReqBody& reqBody,
    std::vector<std::string>& albumIds)
{
    bool ret = false;
    for (size_t i = 0; i < reqBody.albumIds.size(); i++) {
        PhotoAlbumType photoAlbumType = static_cast<PhotoAlbumType>(reqBody.photoAlbumTypes[i]);
        PhotoAlbumSubType photoAlbumSubType = static_cast<PhotoAlbumSubType>(reqBody.photoAlbumSubtypes[i]);
        if (PhotoAlbum::IsHighlightAlbum(photoAlbumType, photoAlbumSubType)) {
            albumIds.emplace_back(reqBody.albumIds[i]);
            ret = true;
        }
    }
    return ret;
}

bool ParameterUtils::CheckEditDataLength(const string& editData)
{
    return editData.size() <= EDIT_DATA_MAX_LENGTH;
}

bool ParameterUtils::CheckOpenUriLength(const string& fileUri)
{
    return fileUri.size() <= PATH_MAX;
}

int32_t ParameterUtils::CheckCreateAssetSubtype(int32_t photoSubtype)
{
    if (photoSubtype < static_cast<int32_t>(PhotoSubType::DEFAULT) ||
        photoSubtype >= static_cast<int32_t>(PhotoSubType::SUBTYPE_END)) {
        return -EINVAL;
    }
    return E_OK;
}

int32_t ParameterUtils::CheckCreateAssetTitle(const std::string &title, bool isSystem)
{
    if (title.empty()) {
        return E_OK;
    }

    if (isSystem) {
        if (MediaFileUtils::CheckTitle(title) != E_OK) {
            return E_INVALID_DISPLAY_NAME;
        }
        return E_OK;
    }

    if (MediaFileUtils::CheckTitleCompatible(title) != E_OK) {
        return E_INVALID_DISPLAY_NAME;
    }
    return E_OK;
}

int32_t ParameterUtils::CheckCreateAssetMediaType(int32_t mediaType, const std::string &extension)
{
    if (mediaType != MEDIA_TYPE_IMAGE && mediaType != MEDIA_TYPE_VIDEO) {
        return -EINVAL;
    }
    string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
    if (MimeTypeUtils::GetMediaTypeFromMimeType(mimeType) != mediaType) {
        return E_CHECK_MEDIATYPE_MATCH_EXTENSION_FAIL;
    }
    return E_OK;
}

int32_t ParameterUtils::CheckCreateAssetCameraShotKey(int32_t photoSubtype, const std::string &cameraShotKey)
{
    if (!cameraShotKey.empty()) {
        if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE ||
            photoSubtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
            return -EINVAL;
        }
    }
    return E_OK;
}

int32_t ParameterUtils::GetTitleAndExtension(const std::string &displayName, std::string &title, std::string &ext)
{
    size_t pos = displayName.find_last_of('.');
    if (pos != std::string::npos) {
        title = displayName.substr(0, pos);
        ext = displayName.substr(pos + 1);
        return E_OK;
    }
    return E_INVALID_DISPLAY_NAME;
}

int32_t ParameterUtils::CheckPublicCreateAsset(const CreateAssetReqBody &reqBody)
{
    int32_t photoSubtype = static_cast<int32_t>(PhotoSubType::DEFAULT);
    CHECK_AND_RETURN_RET_LOG(reqBody.photoSubtype == photoSubtype, -EINVAL, "Invalid photoSubtype");
    CHECK_AND_RETURN_RET_LOG(reqBody.displayName.empty(), -EINVAL, "Invalid displayName");
    CHECK_AND_RETURN_RET_LOG(reqBody.cameraShotKey.empty(), -EINVAL, "Invalid cameraShotKey");

    int32_t errCode = CheckCreateAssetTitle(reqBody.title);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid title");
    errCode = CheckCreateAssetMediaType(reqBody.mediaType, reqBody.extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid mediaType or extension");

    return E_OK;
}

int32_t ParameterUtils::CheckSystemCreateAsset(const CreateAssetReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.title.empty(), -EINVAL, "Invalid title");
    CHECK_AND_RETURN_RET_LOG(reqBody.extension.empty(), -EINVAL, "Invalid extension");

    int32_t errCode = CheckCreateAssetSubtype(reqBody.photoSubtype);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid photoSubtype");
    errCode = CheckCreateAssetCameraShotKey(reqBody.photoSubtype, reqBody.cameraShotKey);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid cameraShotKey");
    errCode = MediaFileUtils::CheckDisplayName(reqBody.displayName);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid displayName");
    std::string extension = MediaFileUtils::GetExtensionFromPath(reqBody.displayName);
    CHECK_AND_RETURN_RET_LOG(!extension.empty(), E_INVALID_DISPLAY_NAME, "Invalid extension");
    errCode = CheckCreateAssetMediaType(reqBody.mediaType, extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid mediaType");

    return E_OK;
}

int32_t ParameterUtils::CheckPublicCreateAssetForApp(const CreateAssetForAppReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.displayName.empty(), -EINVAL, "Invalid displayName");
    CHECK_AND_RETURN_RET_LOG(reqBody.ownerAlbumId.empty(), -EINVAL, "Invalid ownerAlbumId");

    int32_t errCode = CheckCreateAssetSubtype(reqBody.photoSubtype);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid photoSubtype");
    errCode = CheckCreateAssetTitle(reqBody.title);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid title");
    errCode = CheckCreateAssetMediaType(reqBody.mediaType, reqBody.extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid mediaType or extension");

    return E_OK;
}

int32_t ParameterUtils::CheckSystemCreateAssetForApp(const CreateAssetForAppReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.displayName.empty(), -EINVAL, "Invalid displayName");
    CHECK_AND_RETURN_RET_LOG(reqBody.ownerAlbumId.empty(), -EINVAL, "Invalid ownerAlbumId");

    int32_t errCode = CheckCreateAssetSubtype(reqBody.photoSubtype);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid photoSubtype");
    errCode = CheckCreateAssetTitle(reqBody.title, true);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid title");
    errCode = CheckCreateAssetMediaType(reqBody.mediaType, reqBody.extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid mediaType or extension");

    return E_OK;
}

int32_t ParameterUtils::CheckCreateAssetForAppWithAlbum(const CreateAssetForAppReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.displayName.empty(), -EINVAL, "Invalid displayName");

    int32_t errCode = CheckCreateAssetSubtype(reqBody.photoSubtype);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid photoSubtype");
    errCode = CheckCreateAssetTitle(reqBody.title, true);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid title");
    errCode = CheckCreateAssetMediaType(reqBody.mediaType, reqBody.extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid mediaType or extension");

    return E_OK;
}

int32_t ParameterUtils::CheckCreateAssetWithAlbum(const CreateAssetsWithAlbumReqBody &reqBody)
{
    int32_t errCode = CheckCreateAssetTitle(reqBody.title, false);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid title");
    errCode = MediaFileUtils::CheckTitleAndExtensionSize(reqBody.title, reqBody.extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Title and extension size exceeds limit");
    errCode = CheckCreateAssetMediaType(reqBody.mediaType, reqBody.extension);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid mediaType or extension");
    return E_OK;
}

int32_t ParameterUtils::CheckCreatePhotoAlbum(const CreateAlbumReqBody &reqBody)
{
    int32_t errCode = MediaFileUtils::CheckAlbumName(reqBody.albumName);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Invalid albumName");

    return E_OK;
}

int32_t ParameterUtils::CheckTrashPhotos(const std::vector<std::string> &uris)
{
    CHECK_AND_RETURN_RET_LOG(!uris.empty(), -EINVAL, "uris is empty");
    auto size = uris.size();
    CHECK_AND_RETURN_RET_LOG(size <= MAX_TRASH_PHOTOS_SIZE, -EINVAL, "Invalid uris size");

    return E_OK;
}

int32_t ParameterUtils::CheckDeletePhotosCompleted(const std::vector<std::string> &fileIds)
{
    CHECK_AND_RETURN_RET_LOG(!fileIds.empty(), -EINVAL, "fileIds is empty");
    auto size = fileIds.size();
    MEDIA_INFO_LOG("The count of fileIds is %{public}zu", fileIds.size());
    CHECK_AND_RETURN_RET_LOG(size <= MAX_DELETE_PHOTOS_COMPLETED_SIZE, -EINVAL, "Invalid fileIds size");

    return E_OK;
}

bool ParameterUtils::IsPhotoUri(const string& uri)
{
    if (uri.find("../") != string::npos) {
        return false;
    }
    string fileId = MediaFileUri::GetPhotoId(uri);
    return MediaFileUtils::IsValidInteger(fileId);
}

int32_t ParameterUtils::CheckSetAssetTitle(const ModifyAssetsReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileIds.size() == 1, -EINVAL, "Invalid fileIds");
    CHECK_AND_RETURN_RET_LOG(!reqBody.title.empty(), E_INVALID_DISPLAY_NAME, "Invalid title");
    int32_t errCode = MediaFileUtils::CheckTitleCompatible(reqBody.title);
    CHECK_AND_RETURN_RET_LOG(errCode == E_OK, E_INVALID_DISPLAY_NAME, "Invalid title");
    return E_OK;
}

int32_t ParameterUtils::CheckSetAssetPending(const ModifyAssetsReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileIds.size() == 1, -EINVAL, "Invalid fileIds");
    CHECK_AND_RETURN_RET_LOG(reqBody.pending >= 0 && reqBody.pending <= 1, -EINVAL, "Invalid pending");
    return E_OK;
}

int32_t ParameterUtils::CheckSetAssetsFavorite(const ModifyAssetsReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(!reqBody.fileIds.empty(), -EINVAL, "Invalid fileIds");
    CHECK_AND_RETURN_RET_LOG(reqBody.favorite >= 0 && reqBody.favorite <= 1, -EINVAL, "Invalid favorite");
    return E_OK;
}

int32_t ParameterUtils::CheckSetAssetsHiddenStatus(const ModifyAssetsReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(!reqBody.fileIds.empty(), -EINVAL, "Invalid fileIds");
    CHECK_AND_RETURN_RET_LOG(reqBody.hiddenStatus >= 0 && reqBody.hiddenStatus <= 1,
        -EINVAL, "Invalid hiddenStatus");
    return E_OK;
}

int32_t ParameterUtils::CheckSetAssetsRecentShowStatus(const ModifyAssetsReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(!reqBody.fileIds.empty(), -EINVAL, "Invalid fileIds");
    CHECK_AND_RETURN_RET_LOG(reqBody.recentShowStatus >= 0 && reqBody.recentShowStatus <= 1,
        -EINVAL, "Invalid recentShowStatus");
    return E_OK;
}

int32_t ParameterUtils::CheckSetAssetsUserComment(const ModifyAssetsReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(!reqBody.fileIds.empty(), -EINVAL, "Invalid fileIds");
    return E_OK;
}

int32_t ParameterUtils::CheckAddAssetVisitCount(int32_t fileId, int32_t visitType)
{
    CHECK_AND_RETURN_RET_LOG(fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(visitType >= 0 && visitType <= 1, -EINVAL, "Invalid visitType");
    return E_OK;
}

int32_t ParameterUtils::CheckUserComment(const AssetChangeReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(reqBody.userComment.length() <= USER_COMMENT_MAX_LEN, -EINVAL, "user comment too long");

    return E_OK;
}

int32_t ParameterUtils::CheckCameraShotKey(const AssetChangeReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(!reqBody.cameraShotKey.empty() && reqBody.cameraShotKey.size() >= CAMERA_SHOT_KEY_SIZE,
        -EINVAL,
        "Invalid cameraShotKey");

    return E_OK;
}

int32_t ParameterUtils::CheckOrientation(const AssetChangeReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(SUPPORTED_ORIENTATION.count(reqBody.orientation), -EINVAL, "Invalid orientation");

    return E_OK;
}

int32_t ParameterUtils::CheckVideoEnhancementAttr(const AssetChangeReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(reqBody.photoId.size() <= MAX_PHOTO_ID_LEN, -EINVAL, "Invalid photoId");

    return E_OK;
}

int32_t ParameterUtils::CheckWatermarkType(const AssetChangeReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(
        MediaFileUtils::CheckSupportedWatermarkType(reqBody.watermarkType), -EINVAL, "Invalid watermarkType");

    return E_OK;
}

int32_t ParameterUtils::CheckCompositeDisplayMode(const AssetChangeReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.fileId > 0, -EINVAL, "fileId is invalid");
    CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CheckCompositeDisplayMode(reqBody.compositeDisplayMode),
        -EINVAL, "Invalid compositeDisplayMode");

    return E_OK;
}

int32_t ParameterUtils::CheckWhereClause(const std::string &whereClause)
{
    int32_t ret = E_OK;
    MEDIA_DEBUG_LOG("CheckWhereClause start");
    if (!MediaLibraryCommonUtils::CheckWhereClause(whereClause)) {
        ret = E_INVALID_VALUES;
        MEDIA_ERR_LOG("illegal query whereClause input %{private}s", whereClause.c_str());
        VariantMap map = {
            {KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, ret}, {KEY_OPT_TYPE, OptType::QUERY}};
        PostEventUtils::GetInstance().PostErrorProcess(ErrType::DB_OPT_ERR, map);
    }
    MEDIA_DEBUG_LOG("CheckWhereClause end");
    return ret;
}

bool ParameterUtils::CheckPhotoUri(const string &uri)
{
    if (uri.find("../") != string::npos) {
        return false;
    }
    string photoUriPrefix = "file://media/Photo/";
    return MediaStringUtils::StartsWith(uri, photoUriPrefix);
}

int32_t ParameterUtils::CheckRestore(const RestoreReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(PermissionUtils::IsNativeSAApp(), E_CHECK_NATIVE_SA_FAIL, "caller is not native SA.");
    CHECK_AND_RETURN_RET_LOG(reqBody.dbPath.find("..") == string::npos, E_INVALID_PATH, "dbPath is crossing.");
    CHECK_AND_RETURN_RET_LOG(!reqBody.albumLpath.empty(), E_INVALID_VALUES, "albumLpath is empty.");
    CHECK_AND_RETURN_RET_LOG(reqBody.albumLpath.find("..") == string::npos, E_INVALID_PATH, "albumLpath is crossing.");
    CHECK_AND_RETURN_RET_LOG(!reqBody.keyPath.empty(), E_INVALID_VALUES, "keyPath is empty.");
    CHECK_AND_RETURN_RET_LOG(reqBody.keyPath.find("..") == string::npos, E_INVALID_PATH, "keyPath is crossing.");
    CHECK_AND_RETURN_RET_LOG(!reqBody.bundleName.empty(), E_INVALID_VALUES, "bundleName is empty.");
    CHECK_AND_RETURN_RET_LOG(!reqBody.appName.empty(), E_INVALID_VALUES, "appName is empty.");
    return E_OK;
}

int32_t ParameterUtils::CheckCancelRequest(const CancelRequestReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(reqBody.photoId.size() <= MAX_PHOTO_ID_LEN, -EINVAL, "Invalid photoId");
    return E_OK;
}

int32_t ParameterUtils::CheckCreateFileMgrAsset(const CreateFileMgrAssetReqBody &reqBody)
{
    CHECK_AND_RETURN_RET_LOG(!reqBody.displayName.empty(), -EINVAL, "Invalid displayName");
    CHECK_AND_RETURN_RET_LOG(!reqBody.ownerAlbumId.empty(), -EINVAL, "Invalid ownerAlbumId");
    return E_OK;
}
}  // namespace Media
}  // namespace OHOS