/*
 * Copyright (c) KylinSoft  Co., Ltd. 2024. All rights reserved.
 *
 * kaiming is licensed under the GPL v2.0+.
 * 
 * See the LICENSE file for more details.
 */

#include <sys/ioctl.h>
#include <unistd.h>
#include <thread>
#include <atomic>
#include <string>
#include <iostream>

#include "KMPackageManager.h"

#include "common/KMLogger.h"
#include "common/KMInstalledAppQuery.h"
#include "common/KMDbusJson.h"
#include "common/KMVersion.h"
#include "common/KMStringUtils.h"
#include "common/KMFileUtils.h"

#define TEST_ONLINE 1

static vector<KMPMRef> globalRefDownloadListForProgress;         // 实际上需要安装的软件列表,用于进度展示
static KMPMProgressCallBack globalProgressCallback;              // 回调函数
static KMPMProgressStatus globalProgressStatus = {"", 0, "", 5}; // 安装进度回调函数参数
static string progressJson = "";

static string lastOutput;        // 保存最后一次进度条输出
static string preRemaining = ""; // 保存先前的剩余时间

static int currentPercent = 0; // 当前进度

std::atomic<int> sharedValue(0); // 定义一个原子类型的共享变量，初始值为0

std::once_flag KMPackageManager::initFlag;
std::vector<std::string> KMPackageManager::drivers;

class KMPackageManager::Private
{
public:
    std::shared_ptr<KMFolder> m_folder;
    std::shared_ptr<KMCurl> m_curl;
    std::shared_ptr<KMUtil> m_util;
    std::shared_ptr<KMEnv> m_env;
    std::shared_ptr<KMParseSummaryJson> m_parseSummaryJson; // 解析 summary.json
    std::shared_ptr<KMFormatter> m_formatter;               // 格式化输出
    string m_repoPath;                                      // 仓库路径
    bool m_pmIsForceInstall = false;                        //
    KMPMRef m_pmRef;                                        // 单独ref,用于存储到 d->m_refUserList中
    vector<KMPMRef> m_pmRefDownloadList;                    // 实际上需要安装的软件列表
    vector<KMPMRef> m_pmRefOfflineList;                     // 实际上需要安装的软件列表
    vector<KMPMRef> m_pmRefSearchList;                      // 查询的软件列表
    vector<string> m_pmFuzzyMatchRefs;                      // 从依赖文件中模糊匹配到的 ref 列表
    vector<KMRef> m_pmQueryVector;                          // 本地指定信息安装列表
    vector<KMRef> m_pmUninstallVector;                      // 卸载列表
    vector<string> m_pmOldAVersion;                         // 旧版本app
    vector<string> m_pmSpecialIdVersion;                    // 特殊版本app
    vector<string> m_pmReserveDepend;                       // 保留depend依赖
    map<string, KMPMRef> m_pmRefMap;                        // 存储所有ref的map表
    set<string> m_installedFiles;                           // 存储所有已安装的文件列表
    stack<string> m_pmRelatedRefs;                          // 先遍历运行时，再遍历app。因此先压入app,之后提取的时候顺序不会乱
    vector<string> m_pmDownloadRefs;                        // 先遍历运行时，再遍历app。因此先压入app,之后提取的时候顺序不会乱
    vector<string> m_pmDependRefs;                          // 先遍历运行时，再遍历app。因此先压入app,之后提取的时候顺序不会乱

    map<string, KMRef> m_mapRefs; //ref映射表
    shared_ptr<KMOSTreeHandler> m_ostreeHandler;
    shared_ptr<KMOKFile> m_okFile;              // ok 文件解压
    shared_ptr<KMOABMetadata> m_okMetadata;     // ok 文件解压中的 metadata 数据
    shared_ptr<KMHostAppDeploy> m_hostAppDepoy; // hostapp deploy
};

KMPackageManager::KMPackageManager()
    : d(make_shared<Private>())
{
    d->m_folder = shared_ptr<KMFolder>(new KMFolder(KAIMING_SYSTEM_PATH, false));
    d->m_curl = shared_ptr<KMCurl>(new KMCurl());
    d->m_util = shared_ptr<KMUtil>(new KMUtil());
    d->m_env = shared_ptr<KMEnv>(new KMEnv());
    d->m_parseSummaryJson = shared_ptr<KMParseSummaryJson>(new KMParseSummaryJson());
    d->m_formatter = shared_ptr<KMFormatter>(new KMFormatter());

    //智能指针构造函数初始化
    d->m_ostreeHandler = shared_ptr<KMOSTreeHandler>(new KMOSTreeHandler(d->m_folder->getRepoPath())); //opt/kaiming/repo
    d->m_mapRefs = d->m_ostreeHandler->getLocalRefs(BASE_REOMTE);
    d->m_okFile = shared_ptr<KMOKFile>(new KMOKFile());               // ok 文件解压
    d->m_okMetadata = shared_ptr<KMOABMetadata>(new KMOABMetadata()); // ok 文件解压中的 metadata 数据
    d->m_hostAppDepoy = std::make_shared<KMHostAppDeploy>();
}

KMPackageManager::~KMPackageManager()
{
}

int KMPackageManager::processTask(TaskType taskType, const vector<string> &vectorIds, PackageManagerOptions pmOptions)
{
    // 环境校验
    if (!d->m_env->passEnvCheck())
    {
        kmlogger.error("Failed to check environments!");
        return KM_ERROR_CHECK_ENV_FAILED;
    }

    d->m_folder->ensureRepoForSudo(false);

    // 根据任务类型执行不同的任务
    switch (taskType)
    {
    case TASK_TYPE_INSTALL:
        return install(vectorIds, pmOptions);

    case TASK_TYPE_UPDATE:
        return update(vectorIds, pmOptions);

    case TASK_TYPE_SEARCH:
        return search(vectorIds[0], pmOptions);

    case TASK_TYPE_UNINSTALL:
        return uninstall(vectorIds, pmOptions);

    case TASK_TYPE_REPAIR:
        return repair(vectorIds, pmOptions);
    default:
        break;
    }

    return KM_ERROR_NO;
}

int KMPackageManager::install(const vector<string> &vectorIds, PackageManagerOptions pmOptions)
{
    // 下载和解析清单依赖文件 summary.json
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo

    KMOSTreeHandler ostreeManager(repoPath.string());

    std::cout << _("Search matching packages ...") << std::endl;

    d->m_pmIsForceInstall = pmOptions.force;
    int countOfflinePackages = 0;
    for (auto name : vectorIds)
    {
        kmlogger.debug("Install app %s", name.c_str());
        bool isMatchedRefFlag = false;

        KMPMRef pmRef = d->m_util->parseKMPMRef(name);
        d->m_util->printKMPMRef(name, pmRef);

        // 如果用户指定了 arch，则覆盖默认的 arch
        if (!pmOptions.arch.empty())
        {
            pmRef.ref.arch = pmOptions.arch;
        }

        if (!pmOptions.kind.empty())
        {
            pmRef.ref.kind = pmOptions.kind;
        }

        if (pmRef.refSourceType == KMPACKAGE_SOURCE_TYPE_OK)
        {
            // 开始处理离线包
            ++countOfflinePackages;
        }
    }

    if (countOfflinePackages != 0 && countOfflinePackages != vectorIds.size())
    {
        cout << _("Please check the package is all online package or offline package!") << endl;
        return KM_ERROR_INSTALL_FAILED;
    }

    if (countOfflinePackages != 0)
    {
        // // 暂时先只安装一个离线包，之后优化
        // if (vectorIds.size() > 1)
        // {
        //     cout << _("Only support one offline package!") << endl;
        //     return KM_ERROR_INSTALL_FAILED;
        // }
        return installOfflinePackage(vectorIds, pmOptions);
    }

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);

    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");

    int getSummaryState = getRemoteSummary(summaryUrl, false);
    if (getSummaryState != KM_ERROR_NO)
    {
        kmlogger.error("Get and parse summary.json file error!");
        return getSummaryState;
    }

    // 遍历取得所有符合条件的依赖列表
    int getFuzzyMatchState = getAllFuzzyMatchRefVector(vectorIds, pmOptions, TASK_TYPE_INSTALL);
    if (getFuzzyMatchState != KM_ERROR_NO)
    {
        kmlogger.error("Get fuzzy match ref error!");
        return getFuzzyMatchState;
    }

    // 获取必要安装列表
    getUsefulRefList();
    // 获取真正安装列表
    getDownloadRefList(TASK_TYPE_INSTALL);

    if (d->m_pmRefDownloadList.empty())
    {
        printf("%s\n", _("This app has been installed!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }

    // 展示下载列表信息
    printDownloadRefList(d->m_pmRefDownloadList);

    // 用户选择是否展示信息
    if (!printAssumeYesChoice(pmOptions))
    {
        return KM_ERROR_NOT_INSTALLED;
    };

    // 检测当前网址是否可以访问
    if (KMStringUtils::contains(ostreeRepoUrl, "http"))
    {
        if (KMCurl::checkURL(ostreeRepoUrl, 3))
        {
            kmlogger.debug("URL is accessible!");
        }
        else
        {
            kmlogger.error("Failed to access URL!");
            return KM_ERROR_CURL_CHECK_URL_FAILED;
        }
    }

    // 下载包
    int pullFlag = false;
    pullFlag = ostreeManager.pull(REPO_NAME, d->m_pmDownloadRefs, progressCallback);
    if (!pullFlag)
    {
        return KM_ERROR_PULL_FAILED;
    }
    for (auto &ref : d->m_pmOldAVersion)
    {
        if (!removeSpecificDeployFiles(ref))
        {
            return KM_ERROR_DELETE_DIRECTORY_FAILED;
        }
        if (!d->m_pmIsForceInstall)
        {
            if (!deleteSpecificRefsFromRepo(ref))
            {
                return KM_ERROR_DELETE_REF_TAG_FAILED;
            }
        }
    }

    if (!pmOptions.skipSignatureVerification)
    {
        // 验签
        int verifySign = verifySignature(ostreeManager, pmOptions);
        if (verifySign != KM_ERROR_NO)
        {
            return verifySign;
        }
        else
        {
            // 部署包
            return deploy(ostreeManager);
        }
    }
    else
    {
        kmlogger.info("用户不进行验签，跳过验签步骤");
        // 部署包
        return deploy(ostreeManager);
    }
}

int KMPackageManager::installOfflinePackage(const vector<string> &vectorIds, PackageManagerOptions pmOptions)
{
    vector<string> onlinePackageIds; // 离线包的 id 列表
    map<string, string> mountMap;

    for (auto name : vectorIds)
    {
        kmlogger.debug("Install offline packages %s", name.c_str());
        bool isMatchedRefFlag = false;

        KMPMRef pmRef = d->m_util->parseKMPMRef(name);
        d->m_util->printKMPMRef(name, pmRef);

        // 如果用户指定了 arch，则覆盖默认的 arch
        if (!pmOptions.arch.empty())
        {
            pmRef.ref.arch = pmOptions.arch;
        }

        if (!pmOptions.kind.empty())
        {
            pmRef.ref.kind = pmOptions.kind;
        }

        if (pmRef.refSourceType == KMPACKAGE_SOURCE_TYPE_OK)
        {
            // 开始处理离线包
            int retInstallOKFile = installFromOK(name, onlinePackageIds, pmOptions, mountMap);
            if (retInstallOKFile == KM_ERROR_ALREADY_INSTALLED)
            {
                if (!d->m_pmFuzzyMatchRefs.empty())
                {
                    d->m_pmFuzzyMatchRefs.pop_back();
                }
                continue;
            }
            if (retInstallOKFile == KM_ERROR_LOAD_FILE_FAILED && d->m_pmFuzzyMatchRefs.empty())
            {
                return KM_ERROR_LOAD_FILE_FAILED;
            }
            if (retInstallOKFile == KM_ERROR_NOT_SUPPORT_ARCH)
            {
                return KM_ERROR_NOT_SUPPORT_ARCH;
            }
        }

        for (const auto &ref : d->m_pmFuzzyMatchRefs)
        {
            kmlogger.debug("fuzzy match ref : %s", ref.c_str());
        }

        // 依赖列表去重
        KMUtil::removeDuplicateValues(d->m_pmFuzzyMatchRefs);

        if (d->m_pmFuzzyMatchRefs.empty())
        {
            printf("%s\n", _("This app has been installed!"));
            d->m_okFile->umountOK();
            return KM_ERROR_ALREADY_INSTALLED;
        }
    }

    for (auto it = onlinePackageIds.begin(); it != onlinePackageIds.end();)
    {
        string onlinId = *it;
        KMPMRef idRef = d->m_util->parseKMPMRef(onlinId);
        bool isMatchedRefFlag = false;
        for (auto ref : d->m_pmFuzzyMatchRefs)
        {
            KMPMRef fuzzyRef = d->m_util->parseKMPMRef(ref);
            if (idRef.ref.id == fuzzyRef.ref.id && idRef.ref.kind == fuzzyRef.ref.kind && idRef.ref.arch == fuzzyRef.ref.arch && idRef.ref.module == fuzzyRef.ref.module && idRef.ref.channel == fuzzyRef.ref.channel)
            {
                KMVersion idVersion = KMVersion::parse(idRef.ref.version, false);
                KMVersion fuzzyVersion = KMVersion::parse(fuzzyRef.ref.version, false);
                if (idVersion.getMajor() == fuzzyVersion.getMajor() || idRef.ref.version[0] == '0')
                {
                    it = onlinePackageIds.erase(it);
                    isMatchedRefFlag = true;
                    break;
                }
            }
        }
        if (!isMatchedRefFlag)
        {
            it++;
        }
    }

    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo
    KMOSTreeHandler ostreeManager(repoPath.string());
    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);
    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");

    if (!onlinePackageIds.empty())
    {
        d->m_pmFuzzyMatchRefs.clear();
        int getSummaryState = getRemoteSummary(summaryUrl, false);
        if (getSummaryState != KM_ERROR_NO)
        {
            kmlogger.error("Get and parse summary.json file error!");
            return getSummaryState;
        }
        int getFuzzyMatchState = getAllFuzzyMatchRefVector(onlinePackageIds, pmOptions, TASK_TYPE_INSTALL);
        if (getFuzzyMatchState != KM_ERROR_NO)
        {
            d->m_okFile->umountOK();
            kmlogger.error("Get fuzzy match ref error!");
            return getFuzzyMatchState;
        }

        // 获取必要安装列表
        getUsefulRefList();
        // 获取真正安装列表
        getDownloadRefList(TASK_TYPE_INSTALL);
    }

    if (d->m_pmRefOfflineList.empty() && d->m_pmRefDownloadList.empty())
    {
        printf("%s\n", _("This app has been installed!"));
        d->m_okFile->umountOK();
        return KM_ERROR_ALREADY_INSTALLED;
    }
    else if (d->m_pmRefOfflineList.empty() && !d->m_pmRefDownloadList.empty())
    {
        // 展示下载列表信息
        printDownloadRefList(d->m_pmRefDownloadList);

        // 用户选择是否展示信息
        if (!printAssumeYesChoice(pmOptions))
        {
            d->m_okFile->umountOK();
            return KM_ERROR_NOT_INSTALLED;
        }

        // 检测当前网址是否可以访问
        if (KMStringUtils::contains(ostreeRepoUrl, "http"))
        {
            if (KMCurl::checkURL(ostreeRepoUrl, 3))
            {
                kmlogger.debug("URL is accessible!");
            }
            else
            {
                kmlogger.error("Failed to access URL!");
                return KM_ERROR_CURL_CHECK_URL_FAILED;
            }
        }

        // 下载包
        int pullFlag = false;
        pullFlag = ostreeManager.pull(REPO_NAME, d->m_pmDownloadRefs, progressCallback);
        if (!pullFlag)
        {
            d->m_okFile->umountOK();
            return KM_ERROR_PULL_FAILED;
        }

        // 部署在线下载包
        kmlogger.info("Only deploy online package!");
        return deploy(ostreeManager);
    }
    else if (!d->m_pmRefOfflineList.empty() && d->m_pmRefDownloadList.empty())
    {
        // 展示下载列表信息
        printDownloadRefList(d->m_pmRefOfflineList);

        // 用户选择是否展示信息
        if (!printAssumeYesChoice(pmOptions))
        {
            d->m_okFile->umountOK();
            return KM_ERROR_NOT_INSTALLED;
        }

        // 部署离线包
        kmlogger.info("Only deploy offline package!");
        for (auto &ref : d->m_pmOldAVersion)
        {
            if (!removeSpecificDeployFiles(ref))
            {
                return KM_ERROR_DELETE_DIRECTORY_FAILED;
            }
            if (!d->m_pmIsForceInstall)
            {
                if (!deleteSpecificRefsFromRepo(ref))
                {
                    return KM_ERROR_DELETE_REF_TAG_FAILED;
                }
            }
        }

        return deployOfflinePackage(mountMap);
    }
    else
    {
        // 展示下载列表信息
        vector<KMPMRef> allRefList;
        allRefList.insert(allRefList.end(), d->m_pmRefOfflineList.begin(), d->m_pmRefOfflineList.end());
        allRefList.insert(allRefList.end(), d->m_pmRefDownloadList.begin(), d->m_pmRefDownloadList.end());
        printDownloadRefList(allRefList);

        for (auto &offline : d->m_pmRefOfflineList)
        {
            kmlogger.info("offline ref: %s\n", offline.completedRef.c_str());
        }

        for (auto &online : d->m_pmRefDownloadList)
        {
            kmlogger.info("online ref: %s\n", online.completedRef.c_str());
        }

        // 用户选择是否展示信息
        if (!printAssumeYesChoice(pmOptions))
        {
            d->m_okFile->umountOK();
            return KM_ERROR_NOT_INSTALLED;
        }

        // 部署离线包
        kmlogger.info("Deploy offline package!");

        // 检测当前网址是否可以访问
        if (KMStringUtils::contains(ostreeRepoUrl, "http"))
        {
            if (KMCurl::checkURL(ostreeRepoUrl, 3))
            {
                kmlogger.debug("URL is accessible!");
            }
            else
            {
                kmlogger.error("Failed to access URL!");
                return KM_ERROR_CURL_CHECK_URL_FAILED;
            }
        }

        // 下载包
        int pullFlag = false;
        pullFlag = ostreeManager.pull(REPO_NAME, d->m_pmDownloadRefs, progressCallback);
        if (!pullFlag)
        {
            return KM_ERROR_PULL_FAILED;
        }

        // 部署在线下载包
        kmlogger.info("Deploy online package!");
        int retDeploy = deploy(ostreeManager);
        if (retDeploy != KM_ERROR_NO)
        {
            return retDeploy;
        }
        return deployOfflinePackage(mountMap);
    }
}

int KMPackageManager::installSoftwareCenter(string name, string version, int &error, KMPMProgressCallBack installCallback)
{
    kmlogger.debug("begin install");
    globalProgressCallback = installCallback;

    int ret = KM_ERROR_NOTHING_TO_DO;

    PackageManagerOptions pmOption;
    vector<string> vecInstall;

    pmOption.assumeYes = true;
    pmOption.skipSignatureVerification = true;

    vecInstall.push_back(name);

    ret = install(vecInstall, pmOption);

    error = ret;

    kmlogger.debug("end install");
    return ret;
}

int KMPackageManager::updateSoftwareCenter(string name, string version, int &error, KMPMProgressCallBack updateCallback)
{
    kmlogger.debug("begin update");
    globalProgressCallback = updateCallback;

    int ret = KM_ERROR_NOTHING_TO_DO;

    PackageManagerOptions pmOption;
    vector<string> vecUpdate;

    pmOption.assumeYes = true;

    vecUpdate.push_back(name);

    ret = update(vecUpdate, pmOption);

    error = ret;

    kmlogger.debug("end update");
    return ret;
}

int KMPackageManager::uninstallSoftwareCenter(string name, int &error)
{
    kmlogger.debug("begin uninstall");

    int ret = KM_ERROR_NOTHING_TO_DO;

    PackageManagerOptions pmOption;
    vector<string> vecUninstall;

    pmOption.assumeYes = true;

    vecUninstall.push_back(name);

    ret = uninstall(vecUninstall, pmOption);

    error = ret;

    kmlogger.debug("end uninstall");
    return ret;
}

int KMPackageManager::installFromFile()
{
    return 0;
}

int KMPackageManager::installFromOK(const string &name, vector<string> &onlinePackageIds, PackageManagerOptions pmOptions, std::map<string, string> &mountMap)
{
    d->m_okMetadata->layers.clear();
    size_t pos = name.find(".ok");
    string mountPlace = "/tmp/" + name.substr(0, pos);
    fs::path mountPoint = mountPlace;

    d->m_okFile->setMountPoint(mountPoint.string());
    // d->m_okFile->setOKFilePath(name);

    if (!d->m_okFile->loadOKFile(name))
    {
        std::cout << "Failed to load file: " << name << std::endl;
        return KM_ERROR_LOAD_FILE_FAILED;
    }

    d->m_okFile->mountOK();
    d->m_okMetadata = d->m_okFile->getMetadata();
    std::vector<KMInfoJson> layers = d->m_okMetadata->layers;

    if (layers.empty())
    {
        kmlogger.error("No layers found in OK file!");
        return KM_ERROR_NO_LAYERS_FOUND;
    }

    if (layers.size() == 1)
    {
        for (auto layer : layers)
        {
            KMPMRef pmRef;
            string base = layer.base;
            string runtime = layer.runtime;
            vector<string> depends = layer.annotations.depends;
            pmRef.ref.id = layer.id;
            pmRef.ref.channel = layer.channel;
            pmRef.ref.version = layer.version;
            pmRef.ref.module = layer.module;
            pmRef.ref.kind = layer.kind;
            pmRef.installedSize = layer.size;
            pmRef.name = layer.name;
            pmRef.description = layer.description;
            mountMap[layer.id] = mountPoint;

            for (auto arch : layer.archs)
            {
                if (arch == KMUtil::kmGetArch())
                {
                    pmRef.ref.arch = arch;
                }
            }

            pmRef.completedRef = KMUtil::dupKMPMCompletedRef(pmRef);
            d->m_pmRefMap[layer.id] = pmRef;

            if (pmRef.ref.arch.empty())
            {
                std::cout << "Not support this arch" << std::endl;
                return KM_ERROR_NOT_SUPPORT_ARCH;
            }

            if (currentRefIsInstalled(pmRef))
            {
                //不强制安装已经安装的应用
                if (!pmOptions.force)
                {
                    return KM_ERROR_FORCE_INSTALL;
                }

                std::string removeStr;

                if (pmRef.ref.module == "binary")
                {
                    fs::path rootPath = d->m_folder->getLayersPath();
                    removeStr = rootPath.string() + "/" + pmRef.completedRef;
                }

                if (pmRef.ref.module == "devel")
                {
                    fs::path develDir = fs::path(KMStorageDir::getUserBaseDirLocation());
                    removeStr = develDir.string() + "/" + pmRef.completedRef;
                }
                removeSpecificDeployFiles(removeStr);
            }

            std::string completedRef = pmRef.ref.id + "/" + pmRef.ref.version + "/" + pmRef.ref.module + "/" + pmRef.ref.channel + "/" + pmRef.ref.arch;
            d->m_pmFuzzyMatchRefs.push_back(completedRef);
            d->m_pmRefOfflineList.push_back(pmRef);

            if (pmRef.ref.kind != "base")
            {
                if (!runtime.empty())
                {
                    KMPMRef pmRuntimeRef = KMUtil::parseSummaryKMPMRef(runtime);
                    pmRuntimeRef.ref.module = layer.module;
                    std::string runtimeStr = pmRuntimeRef.ref.id + "/" + pmRuntimeRef.ref.version + "/" + layer.module + "/" + layer.channel + "/" + pmRef.ref.arch;

                    if (!d->m_parseSummaryJson->currentFuzzyRefIsInstalled(pmRuntimeRef))
                    {
                        onlinePackageIds.push_back(runtimeStr);
                    }
                }

                if (!base.empty())
                {
                    KMPMRef pmBaseRef = KMUtil::parseSummaryKMPMRef(base);
                    pmBaseRef.ref.module = layer.module;
                    std::string baseStr = pmBaseRef.ref.id + "/" + pmBaseRef.ref.version + "/" + layer.module + "/" + layer.channel + "/" + pmRef.ref.arch;
                    if (!d->m_parseSummaryJson->currentFuzzyRefIsInstalled(pmBaseRef))
                    {
                        onlinePackageIds.push_back(baseStr);
                    }
                }

                if (!depends.empty())
                {
                    for (std::string dependStr : depends)
                    {
                        KMPMRef pmDependRef;
                        std::vector<std::string> tokens;
                        std::stringstream ss(dependStr);
                        std::string token;
                        while (std::getline(ss, token, '/'))
                        {
                            tokens.push_back(token); // 将切分后的部分添加到 tokens 向量中
                        }
                        if (dependStr.find('/') != std::string::npos)
                        {
                            pmDependRef.ref.arch = pmRef.ref.arch;
                            pmDependRef.ref.id = tokens[0];
                            pmDependRef.ref.version = tokens[1];
                            pmDependRef.ref.module = layer.module;
                            pmDependRef.ref.channel = layer.channel;

                            if (!currentFuzzyRefIsInstalled(pmDependRef))
                            {
                                dependStr = dependStr + "/" + layer.module + "/" + layer.channel + "/" + pmRef.ref.arch;
                                onlinePackageIds.push_back(dependStr);
                            }
                        }
                        else
                        {
                            pmDependRef.ref.arch = pmRef.ref.arch;
                            pmDependRef.ref.id = tokens[0];
                            pmDependRef.ref.version = "";
                            pmDependRef.ref.module = layer.module;
                            pmDependRef.ref.channel = layer.channel;
                            if (!currentRefIsUninstalled(pmDependRef))
                            {
                                dependStr = dependStr + "/" + "0.0.0" + "/" + layer.module + "/" + layer.channel + "/" + pmRef.ref.arch;
                                onlinePackageIds.push_back(dependStr);
                            }
                        }
                    }
                }
            }
        }
    }
    else
    {
        for (auto layer : layers)
        {
            KMPMRef pmRef;
            string base = layer.base;
            string runtime = layer.runtime;

            pmRef.ref.id = layer.id;
            pmRef.ref.channel = layer.channel;
            pmRef.ref.version = layer.version;
            pmRef.ref.module = layer.module;
            pmRef.ref.kind = layer.kind;
            pmRef.installedSize = layer.size;
            pmRef.name = layer.name;
            pmRef.description = layer.description;

            for (auto arch : layer.archs)
            {
                if (arch == KMUtil::kmGetArch())
                {
                    pmRef.ref.arch = arch;
                }
            }

            pmRef.completedRef = KMUtil::dupKMPMCompletedRef(pmRef);

            if (pmRef.ref.arch.empty())
            {
                std::cout << "Not support this arch" << std::endl;
                return KM_ERROR_NOT_SUPPORT_ARCH;
            }

            if (currentRefIsInstalled(pmRef))
            {
                //不强制安装已经安装的应用
                if (!pmOptions.force)
                {
                    return KM_ERROR_FORCE_INSTALL;
                }
            }
            d->m_pmRefOfflineList.push_back(pmRef);
        }
    }

    return KM_ERROR_NO;
}

int KMPackageManager::installFromLayer()
{
    return 0;
}

int KMPackageManager::uninstall(const vector<string> &vectorIds, PackageManagerOptions pmOptions)
{
    std::vector<std::string> perUninstallList; // 待删除列表
    // 遍历每个待卸载的应用ID
    for (auto name : vectorIds)
    {
        kmlogger.debug("Uninstall app %s", name.c_str());
        bool isMatchedRefFlag = false;

        KMPMRef pmRef = d->m_util->parseKMPMRef(name);
        d->m_util->printKMPMRef(name, pmRef);
        pmRef.ref.arch = pmOptions.arch;

        if (!currentRefIsUninstalled(pmRef))
        {
            kmlogger.pinfo("%s not installed!", name.c_str());
            continue;
        }
        kmlogger.pinfo("find installed package %s", name.c_str());

        printUninstallList();

        // 用户选择是否展示信息
        if (!printAssumeUninstallYesChoice(pmOptions))
        {
            return KM_ERROR_NOT_UNINSTALLED;
        }

        if (d->m_pmUninstallVector[0].module == "binary")
        {
            fs::path rootPath = d->m_folder->getLayersPath();
            m_infoMap = loadAllInfoJsonFiles(rootPath);
        }
        if (d->m_pmUninstallVector[0].module == "devel")
        {
            fs::path develDir = fs::path(KMStorageDir::getUserBaseDirLocation());
            m_infoMap = loadAllInfoJsonFiles(develDir);
        }

        deleteHostAppFiles();

        if (d->m_pmUninstallVector[0].kind == "app")
        {
            if (pmOptions.deletedataYes)
            {
                deleteUserData(name);
            }

            if (!removeDeployFiles())
            {
                return KM_ERROR_UNINSTALL_FAILED;
            }

            // if (pmOptions.unusedYes)
            // {
            //     // 查找并处理该应用的依赖项
            //     findDependencies(name, perUninstallList);

            // } //默认不删除runtime和base
        }

        vector<KMRef> unRemove = reserveVersion();

        if (d->m_pmUninstallVector[0].kind == "depend")
        {
            if (isContinueUninstall())
            {
                if (!unRemove.empty())
                {
                    d->m_pmReserveDepend.push_back(unRemove[0].id);
                }

                for (auto &uninstallRef : d->m_pmUninstallVector)
                {
                    removeDepend(uninstallRef);
                }
            }
        }

        if (d->m_pmUninstallVector[0].kind == "runtime" || d->m_pmUninstallVector[0].kind == "base")
        {

            for (auto it = d->m_pmUninstallVector.begin(); it != d->m_pmUninstallVector.end(); it++)
            {
                auto &uninstallIt = *it;
                for (auto &queryIt : unRemove)
                {
                    if (uninstallIt.arch == queryIt.arch && uninstallIt.channel == queryIt.channel && uninstallIt.module == queryIt.module)
                    {
                        if (uninstallIt.version != queryIt.version)
                        {
                            KMVersion uninstallVersion = KMVersion::parse(uninstallIt.version, false);
                            KMVersion queryVersion = KMVersion::parse(queryIt.version, false);
                            if (uninstallVersion.getMajor() == queryVersion.getMajor())
                            {
                                // directUninstallVector.push_back(uninstallIt);
                                std::string removeUninstallStr = uninstallIt.baseInstallDir + "/" + uninstallIt.channel + "/" + uninstallIt.arch + "/" + uninstallIt.kind + "/" + uninstallIt.id + "/" + uninstallIt.module + "/" + uninstallIt.version;
                                removeSpecificDeployFiles(removeUninstallStr);
                                deleteSpecificRefsFromRepo(removeUninstallStr);
                                it = d->m_pmUninstallVector.erase(it);
                                it--;
                                break;
                            }
                        }
                    }
                }
            }

            printUninstallDependsOnList();

            if (isContinueUninstall() && !d->m_pmUninstallVector.empty())
            {
                for (auto it = d->m_pmUninstallVector.begin(); it != d->m_pmUninstallVector.end(); it++)
                {
                    auto &uninstallIt = *it;
                    std::string findStr = uninstallIt.channel + ":" + uninstallIt.id + "/" + uninstallIt.version[0];

                    bool foundAny = false;
                    for (auto it = m_infoMap.begin(); it != m_infoMap.end();)
                    {
                        auto pair = *it;
                        KMInfoJson &info = pair.second;
                        // std::string str=info[uninstall]
                        if (info[uninstallIt.kind].find(findStr) != std::string::npos && info[uninstallIt.kind].find(uninstallIt.arch) != std::string::npos && info.module == uninstallIt.module)
                        {
                            if (info.kind == "runtime")
                            {
                                std::string runtimeStr = info.channel + ":" + info.id + "/" + info.version[0];
                                for (auto secondIt = m_infoMap.begin(); secondIt != m_infoMap.end();)
                                {
                                    auto secondPair = *secondIt;
                                    KMInfoJson &secondInfo = secondPair.second;
                                    if (secondInfo[info.kind].find(runtimeStr) != std::string::npos && secondInfo[info.kind].find(uninstallIt.arch) != std::string::npos && secondInfo.module == uninstallIt.module)
                                    {
                                        std::string removeSecondStr = secondPair.first;
                                        removeSpecificDeployFiles(removeSecondStr);
                                        secondIt = m_infoMap.erase(secondIt);
                                        deleteSpecificRefsFromRepo(removeSecondStr);
                                    }
                                    else
                                    {
                                        secondIt++;
                                    }
                                }
                            }
                            if (info.kind == "depend")
                            {
                                KMRef dependRef;
                                dependRef.id = info.id;
                                dependRef.kind = info.kind;
                                dependRef.module = info.module;
                                dependRef.arch = d->m_pmUninstallVector[0].arch;
                                dependRef.version = info.version;
                                dependRef.baseInstallDir = fs::path(KMStorageDir::getUserBaseDirLocation());
                                removeDepend(dependRef);
                            }
                            std::string removeStr = pair.first;

                            // if is hostapp delete first
                            d->m_hostAppDepoy->setHostAppConfig(removeStr, info.id);
                            if (d->m_hostAppDepoy->loadHostAppInfo())
                            {
                                d->m_hostAppDepoy->uninstall();
                            }
                            removeSpecificDeployFiles(removeStr);
                            deleteSpecificRefsFromRepo(removeStr);

                            it = m_infoMap.erase(it);
                        }
                        else
                        {
                            it++;
                        }
                    }
                    std::string removeUninstallStr = uninstallIt.baseInstallDir + "/" + uninstallIt.channel + "/" + uninstallIt.arch + "/" + uninstallIt.kind + "/" + uninstallIt.id + "/" + uninstallIt.module + "/" + uninstallIt.version;
                    removeSpecificDeployFiles(removeUninstallStr);
                    deleteSpecificRefsFromRepo(removeUninstallStr);
                }
            }
        }

        fs::path infoListFile = d->m_folder->getInfoPath() / (name + ".list");
        fs::remove(infoListFile);
    }
    return KM_ERROR_NO;
}

bool KMPackageManager::removeDepend(const KMRef uninstallRef)
{
    for (auto it = m_infoMap.begin(); it != m_infoMap.end();)
    {
        auto pair = *it;
        KMInfoJson &info = pair.second;
        std::string uninstallArch;
        auto uninstallArchIt = std::find(info.archs.begin(), info.archs.end(), uninstallRef.arch);

        if (uninstallArchIt != info.archs.end())
        {
            uninstallArch = uninstallRef.arch;
        }
        else
        {
            uninstallArch = info.archs[0];
        }

        if (uninstallArch != uninstallRef.arch || info.module != uninstallRef.module || info.channel != uninstallRef.channel)
        {
            it++;
            continue;
        }

        for (auto dependstr : info.annotations.depends)
        {
            if (dependstr.find(uninstallRef.id) != std::string::npos)
            {

                KMVersion uninstallVersion = KMVersion::parse(uninstallRef.version, false);
                uint64_t uninstallVersionStr = uninstallVersion.getMajor();
                std::string dependInfo = uninstallRef.id + "/" + std::to_string(uninstallVersionStr);
                KMRef dependRef;
                dependRef.id = info.id;
                dependRef.kind = info.kind;
                dependRef.module = info.module;
                dependRef.channel = info.channel;
                dependRef.arch = uninstallArch;
                dependRef.version = info.version;
                dependRef.baseInstallDir = fs::path(KMStorageDir::getUserBaseDirLocation());
                if (dependstr.find(dependInfo) != std::string::npos)
                {
                    removeDepend(dependRef);
                }
                else
                {
                    if (!d->m_pmReserveDepend.empty())
                    {
                        for (auto reserver : d->m_pmReserveDepend)
                        {
                            if (reserver == uninstallRef.id)
                            {
                                d->m_pmReserveDepend.push_back(info.id);
                            }
                            else
                            {
                                removeDepend(dependRef);
                            }
                        }
                    }
                    else
                    {
                        removeDepend(dependRef);
                    }
                }
            }
        }
        it++;
    }
    std::string removeUninstallStr = uninstallRef.baseInstallDir + "/" + uninstallRef.channel + "/" + uninstallRef.arch + "/" + uninstallRef.kind + "/" + uninstallRef.id + "/" + uninstallRef.module + "/" + uninstallRef.version;
    removeSpecificDeployFiles(removeUninstallStr);
    return KM_ERROR_NO;
}

bool KMPackageManager::isContinueUninstall()
{
    bool isContinueUninstall = false;
    while (true)
    {
        std::cout << _("The apps, which depends on those packages, will be uninstalled, do you want to continue (Y or N)?");
        std::string input;
        std::getline(std::cin, input);

        // 检查是否输入 'a'
        if (input == "y" || input == "Y")
        {
            isContinueUninstall = true;
            return isContinueUninstall;
        }
        else if (input == "n" || input == "N")
        {
            return isContinueUninstall;
        }
        else
        {
            continue;
        }
    }
}

void KMPackageManager::printUninstallList()
{
    int i = 1;
    printf("\n%-10s %-30s %-15s %-15s %-15s %-15s\n", _(" "), _("ID"), _("Channel"), _("Arch"), _("Module"), _("Version"));
    for (const auto &pmRef : d->m_pmQueryVector)
    {
        printf("%-10d %-30s %-15s %-15s %-15s %-15s\n", i, pmRef.id.c_str(), pmRef.channel.c_str(), pmRef.arch.c_str(), pmRef.module.c_str(), pmRef.version.c_str());
        i++;
    }
}

bool KMPackageManager::removeDeployFiles()
{
    std::set<std::string> allUniqueLines;

    for (auto &it : d->m_pmUninstallVector)
    {
        fs::path versionFile = it.baseInstallDir + "/" + it.channel + "/" + it.arch + "/" + it.kind + "/" + it.id + "/" + it.module + "/" + it.version;
        fs::path deployFile = versionFile / "deploy";

        if (!fs::exists(deployFile))
        {
            // std::cerr << "文件不存在: " << deployFile << std::endl; // 输出调试信息
            continue; // 跳过该文件
        }

        auto lines = KMFolder::readDeployFiles(deployFile);
        allUniqueLines.insert(lines.begin(), lines.end());
    }

    deleteFilesIfExist(allUniqueLines);
    removeEmptyDirs(allUniqueLines);

    return true;
}

void KMPackageManager::deleteHostAppFiles()
{
    for (auto &it : d->m_pmUninstallVector)
    {
        fs::path versionFile = it.baseInstallDir + "/" + it.channel + "/" + it.arch + "/" + it.kind + "/" + it.id + "/" + it.module + "/" + it.version;
        d->m_hostAppDepoy->setHostAppConfig(versionFile, it.id);
        if (d->m_hostAppDepoy->loadHostAppInfo())
        {
            d->m_hostAppDepoy->uninstall();
        }
    }
}

void KMPackageManager::removeEmptyDirs(const std::set<std::string> &files)
{
    for (const auto &file : files)
    {
        fs::path dir = fs::path(file).parent_path();
        while (dir != "/" && fs::exists(dir) && fs::is_empty(dir))
        {
            fs::remove(dir);
            KMDebug("Removed empty dir: " + dir.string());
            dir = dir.parent_path();
        }
    }
}

void KMPackageManager::findDependencies(const std::string &targetId, std::vector<std::string> &perUninstallList)
{
    // 检查目标id是否在m_infoMap中
    if (m_infoMap.find(targetId) == m_infoMap.end())
    {
        std::cout << targetId << " not found in info.json files.\n";
        return;
    }

    // 获取目标应用的info.json
    KMInfoJson targetInfo = m_infoMap[targetId];
    m_infoMap.erase(targetId); // 移除目标应用，避免重复处理

    std::string extractRuntimeName, extractBaseName;

    // Step 1: 查找不被其他应用所依赖的runtime
    if (!targetInfo.runtime.empty())
    {
        KMRef runtimeRef = targetInfo.runtimeRef();
        extractRuntimeName = runtimeRef.id;
        m_infoMap.erase(extractRuntimeName);
        // 检查 runtime 是否被其他应用依赖
        bool isRuntimeDepended = false;
        for (const auto &pair : m_infoMap)
        {
            const KMInfoJson &info = pair.second;
            if ((info.runtimeRef().id == extractRuntimeName) && (info.id != targetId))
            {
                isRuntimeDepended = true;
                m_infoMap.erase(info.id);
                break;
            }
        }
        // 如果 runtime 不被依赖，加入 perUninstallList
        if (!isRuntimeDepended)
        {
            perUninstallList.push_back(extractRuntimeName);

            // Step 2: 查找不被runtime或app依赖的base
            if (!targetInfo.base.empty())
            {
                KMRef baseRef = targetInfo.baseRef();
                extractBaseName = baseRef.id;
                m_infoMap.erase(extractBaseName);
                // 检查 base 是否被应用或 runtime 依赖
                bool isBaseDepended = false;
                for (const auto &pair : m_infoMap)
                {
                    const KMInfoJson &info = pair.second;
                    if ((info.baseRef().id == extractBaseName) && (info.id != targetId))
                    {
                        isBaseDepended = true;
                        m_infoMap.erase(info.id);
                        break;
                    }
                }

                // 如果 base 不被依赖，加入 perUninstallList
                if (!isBaseDepended)
                {
                    perUninstallList.push_back(extractBaseName);
                    m_infoMap.erase(extractBaseName); // 从 m_infoMap 中移除
                }
            }
        }
    }
    // 输出处理结果
    std::cout << "Dependencies for " << targetId << " have been processed.\n";
}

std::unordered_map<std::string, KMInfoJson> KMPackageManager::loadAllInfoJsonFiles(std::string pathStr)
{
    // fs::path layersPath = d->m_folder->getLayersPath();
    std::unordered_map<std::string, KMInfoJson> infoMap;

    // 遍历目录中的所有info.json文件
    try
    {
        for (const auto &dirEntry : std::filesystem::recursive_directory_iterator(pathStr))
        {
            if (dirEntry.is_regular_file() && dirEntry.path().filename() == "info.json")
            {
                auto filenameStr = dirEntry.path().string();
                KMInfoJson infoJson;
                infoJson.loadFile(filenameStr);

                size_t lastSlashPos = filenameStr.find_last_of('/');
                if (lastSlashPos != std::string::npos)
                {
                    filenameStr = filenameStr.substr(0, lastSlashPos);
                }
                // 使用文件路径作为key存储每个infoJson对象
                infoMap[filenameStr] = infoJson;
            }
        }
    }
    catch (const std::filesystem::filesystem_error &e)
    {
        std::cerr << e.what() << std::endl;
        kmlogger.perror(e.what());
    }

    return infoMap;
}

void KMPackageManager::printUninstallList(const vector<std::string> &uninstallId)
{
    printf("\n%-30s %-30s\n", _("ID"), _("Arch"));
    for (const auto &id : uninstallId)
    {
        KMPMRef pmRef = d->m_util->parseKMPMRef(id);
        printf("%-30s %-30s\n", pmRef.ref.id.c_str(), pmRef.ref.arch.c_str());
    }
}

bool KMPackageManager::printAssumeUninstallYesChoice(PackageManagerOptions pmOptions)
{
    if (!pmOptions.assumeYes)
    {
        while (true)
        {
            // yesOption = std::cin.get();
            std::cout << _("Enter number to delete (separated by spaces) or 'y' to delete all, enter 'n' to cancel: ");
            d->m_pmUninstallVector.clear();
            std::string input;
            std::getline(std::cin, input);

            // 检查是否输入 'a'
            if (input == "y" || input == "Y")
            {
                d->m_pmUninstallVector = d->m_pmQueryVector;
                // pmOptions.assumeYes = true;
                break;
            }

            if (input == "n" || input == "N")
            {
                return false;
            }

            std::istringstream iss(input);
            std::vector<int> indices;
            int index;
            bool isValid = true;

            if (input.empty())
            {
                std::cout << "Input is empty" << std::endl;
                continue;
            }

            for (char ch : input)
            {
                if (!std::isdigit(ch) && ch != ' ')
                {
                    std::cout << "Invalid idx: " << input << std::endl;
                    isValid = false;
                    break;
                }
            }

            if (!isValid)
            {
                continue;
            }

            while (iss >> index)
            {
                indices.push_back(index);
            }

            indices.erase(std::unique(indices.begin(), indices.end()), indices.end());

            for (int idx : indices)
            {
                if (idx > 0 && idx <= static_cast<int>(d->m_pmQueryVector.size()))
                {
                    d->m_pmUninstallVector.push_back(d->m_pmQueryVector[idx - 1]);
                }
                else
                {
                    std::cout << "Invalid index: " << idx << std::endl;
                    isValid = false;
                }
            }

            if (!isValid)
            {
                continue;
            }

            break;
        }
    }
    else
    {
        d->m_pmUninstallVector = d->m_pmQueryVector;
    }

    return true;
}

vector<KMRef> KMPackageManager::reserveVersion()
{
    vector<KMRef> unRemove = d->m_pmQueryVector;
    for (auto &it : d->m_pmUninstallVector)
    {
        unRemove.erase(std::remove_if(unRemove.begin(), unRemove.end(), [&](const KMRef &nowIt)
                                      { return it.arch == nowIt.arch && it.module == nowIt.module && it.version == nowIt.version; }),
                       unRemove.end());
    }
    return unRemove;
}

bool KMPackageManager::listDeployFiles(const std::string &name)
{
    std::vector<fs::path> idPaths;
    fs::path rootDir = d->m_folder->getLayersPath();
    KMFolder::findIdPaths(rootDir, name, idPaths);

    if (idPaths.empty())
    {
        std::cerr << "No ID paths found for ID: " << name << std::endl;
        return false;
    }

    std::cout << "ID paths found: " << std::endl;
    for (const auto &path : idPaths)
    {
        std::cout << "  " << path << std::endl;
    }

    // Step 2: Find deploy files in each ID path
    std::vector<fs::path> deployFiles;
    for (const auto &idPath : idPaths)
    {
        KMFolder::findDeployFiles(idPath, deployFiles);
    }

    if (deployFiles.empty())
    {
        std::cerr << "No deploy files found for ID: " << name << std::endl;
        return false;
    }

    std::cout << "Deploy files found: " << std::endl;
    for (const auto &file : deployFiles)
    {
        std::cout << "  " << file << std::endl;
    }

    // Step 3: Read deploy files and collect unique lines
    std::set<std::string> allUniqueLines;
    for (const auto &deployFile : deployFiles)
    {
        auto lines = KMFolder::readDeployFiles(deployFile);
        allUniqueLines.insert(lines.begin(), lines.end());
    }

    // Step 4: Output and delete unique lines
    for (auto file : allUniqueLines)
    {
        std::cout << file << std::endl;
    }

    return true;
}

bool KMPackageManager::removeDeployFiles(const std::string &name)
{
    std::vector<fs::path> idPaths;

    fs::path rootDir = d->m_folder->getLayersPath();
    fs::path develDir = fs::path(KMStorageDir::getUserBaseDirLocation());

    KMFolder::findIdPaths(rootDir, name, idPaths);
    if (fs::exists(develDir))
    {
        KMFolder::findIdPaths(develDir, name, idPaths);
    }
    if (idPaths.empty())
    {
        // std::cerr << "No ID paths found for ID: " << name << std::endl;
        return false;
    }

    std::cout << "ID paths found: " << std::endl;
    for (const auto &path : idPaths)
    {
        std::cout << "  " << path << std::endl;
    }

    // Step 2: Find deploy files in each ID path
    std::vector<fs::path> deployFiles;
    for (const auto &idPath : idPaths)
    {
        KMFolder::findDeployFiles(idPath, deployFiles);
    }

    if (deployFiles.empty())
    {
        std::cerr << "No deploy files found for ID: " << name << std::endl;
        return false;
    }

    std::cout << "Deploy files found: " << std::endl;
    for (const auto &file : deployFiles)
    {
        std::cout << "  " << file << std::endl;
    }

    // Step 3: Read deploy files and collect unique lines
    std::set<std::string> allUniqueLines;
    for (const auto &deployFile : deployFiles)
    {
        auto lines = KMFolder::readDeployFiles(deployFile);
        allUniqueLines.insert(lines.begin(), lines.end());
    }

    // Step 4: Output and delete unique lines
    deleteFilesIfExist(allUniqueLines);

    return true;
}

bool KMPackageManager::removeTmpDeployFiles(const std::string &name)
{
    std::vector<fs::path> idPaths;

    fs::path rootDir = fs::path("/tmp");
    fs::path develDir = fs::path(KMStorageDir::getUserBaseDirLocation());

    KMFolder::findTmpIdPaths(rootDir, name, idPaths);
    if (fs::exists(develDir))
    {
        KMFolder::findIdPaths(develDir, name, idPaths);
    }
    if (idPaths.empty())
    {
        kmlogger.info("No ID paths found for ID: %s", name.c_str());
        return false;
    }

    kmlogger.info("ID paths found:");
    for (const auto &path : idPaths)
    {
        kmlogger.info("  %s", path.c_str());
    }

    for (const auto &path : idPaths)
    {
        if (fs::exists(path))
        {
            kmlogger.info("Deleting: %s", path.c_str());
            fs::remove_all(path);
        }
    }

    return true;
}

bool KMPackageManager::removeSpecificDeployFiles(const std::string &str)
{
    std::set<std::string> allUniqueLines;
    fs::path versionFile = str + "/" + "deploy";

    if (!fs::exists(versionFile))
    {
        // std::cerr << "文件不存在: " << deployFile << std::endl; // 输出调试信息
        return false; // 跳过该文件
    }

    auto lines = KMFolder::readDeployFiles(versionFile);
    allUniqueLines.insert(lines.begin(), lines.end());

    deleteFilesIfExist(allUniqueLines);
    removeEmptyDirs(allUniqueLines);
    return true;
}

void KMPackageManager::deleteFilesIfExist(const std::set<std::string> &fileList)
{
    for (const auto &filePath : fileList)
    {
        try
        {
            if (fs::exists(filePath))
            {
                std::cout << "File exists: " << filePath << ". Deleting..." << std::endl;
                fs::remove_all(filePath);
            }
            else
            {
                // std::cout << "File does not exist: " << filePath << ". Skipping..." << std::endl;
            }
        }
        catch (const fs::filesystem_error &e)
        {
            std::cerr << "Error processing file: " << filePath << ". Error: " << e.what() << std::endl;
        }
    }
}

bool KMPackageManager::deleteRefsFromRepo(const std::string &name)
{
    // 从本地repo中删除引用
    for (auto pair : d->m_mapRefs)
    {
        if (pair.second.id == name)
        {
            string refString = pair.second.branch + "/" + pair.second.arch + "/" + pair.second.kind + "/" + pair.second.id + "/" + pair.second.module + "/" + pair.second.version;

            if (!d->m_ostreeHandler->deleteRefTag("", string("deploy/").append(refString)))
            {
                return false;
            }

            if (!d->m_ostreeHandler->deleteRefTag(BASE_REOMTE, refString)) // file:///opt/kaiming/repo/refs/remotes/kaiming-repo/stable/x86_64/app/top.openkylin.Music
            {
                return false;
            }

            if (!d->m_ostreeHandler->repoPrune())
            {
                return false;
            }
        }
    }
    return true;
}

bool KMPackageManager::deleteSpecificRefsFromRepo(const std::string &str)
{
    // 找到第4个 '/' 的位置
    size_t pos = 0;
    int slashCount = 0;
    while (slashCount < 3 && pos != std::string::npos)
    {
        pos = str.find('/', pos + 1);
        slashCount++;
    }
    // 提取第4个 '/' 后面的内容
    std::string extractedStr = (pos != std::string::npos) ? str.substr(pos + 1) : "";
    // 从本地repo中删除引用
    for (auto pair : d->m_mapRefs)
    {
        string refString = pair.second.branch + "/" + pair.second.arch + "/" + pair.second.kind + "/" + pair.second.id + "/" + pair.second.module + "/" + pair.second.version;

        if (refString == extractedStr)
        {
            if (!d->m_ostreeHandler->deleteRefTag("", string("deploy/").append(refString)))
            {
                return false;
            }

            if (!d->m_ostreeHandler->deleteRefTag(BASE_REOMTE, refString)) // file:///opt/kaiming/repo/refs/remotes/kaiming-repo/stable/x86_64/app/top.openkylin.Music
            {
                return false;
            }

            if (!d->m_ostreeHandler->repoPrune())
            {
                return false;
            }
            break;
        }
    }

    return true;
}

bool KMPackageManager::deleteUserData(const std::string &name)
{
    printf("remove app %s user data dir.\n", name.c_str());

    if (!fs::remove_all(d->m_folder->getAppDataPath(name)))
    {
        kmlogger.error("uninstall %s error, can't delete the directory.", name);
        return false;
    }
    return true;
}

int KMPackageManager::update(const vector<string> &vectorIds, PackageManagerOptions pmOptions)
{
    // 下载和解析清单依赖文件 summary.json
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo

    KMOSTreeHandler ostreeManager(repoPath.string());

    std::cout << _("Search matching packages ...") << std::endl;

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);
    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");

    fs::path basePath = d->m_folder->getPath();
    fs::path summaryJsonPath = basePath / "summary.json";
    bool isSummaryJsonExpired = KMFileUtils::isFileExpired(summaryJsonPath, 3600);
    int getSummaryState = getRemoteSummary(summaryUrl, isSummaryJsonExpired);
    if (getSummaryState != KM_ERROR_NO)
    {
        kmlogger.error("Get and parse summary.json file error!");
        return getSummaryState;
    }

    if (vectorIds.empty())
    {
        // 仅更新包依赖清单文件
        return KM_ERROR_NO;
    }

    // 遍历取得所有符合条件的依赖列表
    int getFuzzyMatchState = getAllFuzzyMatchRefVector(vectorIds, pmOptions, TASK_TYPE_UPDATE);
    if (getFuzzyMatchState != KM_ERROR_NO)
    {
        kmlogger.error("Get fuzzy match ref error!");
        return getFuzzyMatchState;
    }
    getUsefulRefList();
    // 获取真正更新列表
    getDownloadRefList(TASK_TYPE_UPDATE);

    if (d->m_pmRefDownloadList.empty())
    {
        printf("%s\n", _("Not need to update!"));
        return KM_ERROR_NOT_NEED_UPDATE;
    }

    // 展示下载列表信息
    printDownloadRefList(d->m_pmRefDownloadList);

    // 用户选择是否展示信息
    if (!printAssumeYesChoice(pmOptions))
    {
        return KM_ERROR_NOT_INSTALLED;
    };

    // 检测当前网址是否可以访问
    if (KMStringUtils::contains(ostreeRepoUrl, "http"))
    {
        if (KMCurl::checkURL(ostreeRepoUrl, 3))
        {
            kmlogger.debug("URL is accessible!");
        }
        else
        {
            kmlogger.error("Failed to access URL!");
            return KM_ERROR_CURL_CHECK_URL_FAILED;
        }
    }

    // 下载包
    int pullFlag = false;
    pullFlag = ostreeManager.pull(REPO_NAME, d->m_pmDownloadRefs, progressCallback);
    if (!pullFlag)
    {
        return KM_ERROR_PULL_FAILED;
    }
    for (auto &ref : d->m_pmOldAVersion)
    {
        if (!removeSpecificDeployFiles(ref))
        {
            return KM_ERROR_DELETE_DIRECTORY_FAILED;
        }
    }
    // 部署包
    return deploy(ostreeManager);
}

int KMPackageManager::dbusSearch(const string &vectorIds, PackageManagerOptions pmOptions)
{
    GError *error = NULL;
    // 连接到 D-Bus 系统总线
    GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
    if (!connection)
    { // 连接失败
        kmlogger.error("Failed to connect to D-Bus: %s", error->message);
        g_clear_error(&error);
    }

    // 调用 getRemoteSummary 方法
    GVariant *result = g_dbus_connection_call_sync(
        connection,
        "org.kylin.kaiming",           // 服务名称
        "/org/kylin/kaiming",          // 对象路径
        "org.kylin.kaiming.interface", // 接口名称
        "getRemoteSummary",            // 方法名  与xml中的方法名一致
        NULL,                          // 传递给 getRemoteSummary 方法的参数
        // g_variant_new("(s)", vectorIds.c_str()), // 参数元组
        NULL, // 返回值类型（NULL 表示不检查）
        G_DBUS_CALL_FLAGS_NONE,
        -1,   // 超时时间,-1 表示默认超时
        NULL, // Cancellable
        &error);

    if (error)
    { // 调用失败
        kmlogger.error("Failed to call getRemoteSummary: %s", error->message);
        g_clear_error(&error);
    }
    else
    {
        gboolean success;
        g_variant_get(result, "(b)", &success); // 假设返回值是布尔值
        kmlogger.debug("getRemoteSummary method call result: %s", success ? "Success" : "Failure");
        g_variant_unref(result); // 释放资源
    }

    g_object_unref(connection); // 释放资源

    fs::path basePath = d->m_folder->getPath();
    fs::path summaryJsonPath = basePath / "summary.json";
    d->m_parseSummaryJson->loadFile(summaryJsonPath);
    string completePath = d->m_parseSummaryJson->printSearchJson(vectorIds, pmOptions.arch, pmOptions.kind, pmOptions.module, pmOptions.isPrint);

    return KM_ERROR_NO;
}

int KMPackageManager::search(const string &vectorIds, PackageManagerOptions pmOptions)
{
    // 下载和解析清单依赖文件 summary.json
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo

    KMOSTreeHandler ostreeManager(repoPath.string());

    std::cout << _("Search matching packages ...") << std::endl;

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);
    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");
    ;

    fs::path basePath = d->m_folder->getPath();
    fs::path summaryJsonPath = basePath / "summary.json";
    bool isSummaryJsonExpired = KMFileUtils::isFileExpired(summaryJsonPath, 3600);
    int getSummaryState = getRemoteSummary(summaryUrl, isSummaryJsonExpired);
    if (getSummaryState != KM_ERROR_NO)
    {
        kmlogger.error("Get and parse summary.json file error!");
        return getSummaryState;
    }
    d->m_parseSummaryJson->loadFile(summaryUrl);
    string completePath = d->m_parseSummaryJson->printSearchJson(vectorIds, pmOptions.arch, pmOptions.kind, pmOptions.module, pmOptions.isPrint);

    return KM_ERROR_NO;
}

string KMPackageManager::searchInfo(const string &vectorIds, PackageManagerOptions pmOptions)
{
    // 下载和解析清单依赖文件 summary.json
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo

    KMOSTreeHandler ostreeManager(repoPath.string());

    std::cout << _("Search matching packages ...") << std::endl;

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);
    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");

    fs::path basePath = d->m_folder->getPath();
    fs::path summaryJsonPath = basePath / "summary.json";
    bool isSummaryJsonExpired = KMFileUtils::isFileExpired(summaryJsonPath, 3600);
    int getSummaryState = getRemoteSummary(summaryUrl, isSummaryJsonExpired);
    if (getSummaryState != KM_ERROR_NO)
    {
        kmlogger.error("Get and parse summary.json file error!");
        return "";
    }
    d->m_parseSummaryJson->loadFile(summaryUrl);
    pmOptions.arch = KMUtil::kmGetArch();
    string completePath = d->m_parseSummaryJson->printSearchJson(vectorIds, pmOptions.arch, pmOptions.kind, pmOptions.module, pmOptions.isPrint);

    return completePath;
}

int KMPackageManager::repair(const vector<string> &vectorIds, PackageManagerOptions pmOptions)
{
    // 下载和解析清单依赖文件 summary.json
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo

    KMOSTreeHandler ostreeManager(repoPath.string());

    std::cout << _("Search matching packages ...") << std::endl;

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);

    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");

    int getSummaryState = getRemoteSummary(summaryUrl, false);
    if (getSummaryState != KM_ERROR_NO)
    {
        kmlogger.error("Get and parse summary.json file error!");
        return getSummaryState;
    }

    // 遍历取得所有符合条件的依赖列表
    int getFuzzyMatchState = getAllFuzzyMatchRefVector(vectorIds, pmOptions, TASK_TYPE_REPAIR);
    if (getFuzzyMatchState != KM_ERROR_NO)
    {
        kmlogger.error("Get fuzzy match ref error!");
        return getFuzzyMatchState;
    }
    getUsefulRefList();
    // 获取真正安装列表
    getDownloadRefList(TASK_TYPE_REPAIR);

    if (d->m_pmRefDownloadList.empty())
    {
        printf("%s\n", _("This app has been installed!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }

    // 进行损坏检测，过滤掉未损坏的应用
    auto it = d->m_pmRefDownloadList.begin();
    while (it != d->m_pmRefDownloadList.end())
    {
        KMPMRef ref = *(it);

        // 对修复的应用包files做md5判断，如果计算得到的md5与原md5一致则该包不损坏，跳过修复
        fs::path layersPath = d->m_folder->getLayersPath();

        // 计算出files的md5
        std::string filesDirPath = KMStringUtils::buildFilename(layersPath, ref.completedRef);
        std::string filesDirFiles = KMStringUtils::buildFilename(filesDirPath, "files");
        std::string checksum = KMFileUtils::getDirMd5sum(filesDirFiles);
        std::string filesMd5 = KMStringUtils::buildFilename(filesDirPath, "files.md5");
        std::string filePrefix; // 读取出本地md5文件的值

        // 读取md5的文件不存在，该包存在修复列表中
        if (!fs::exists(filesMd5))
        {
            ++it; //迭代计算下一个文件
        }
        else
        {
            //读取之前判断md5是否存在
            KMFileUtils::readFile(filesMd5, filePrefix);

            // 如果本地的Md5的文件与计算出来的Md5文件相同，则该app/base/runtime则不需要修复
            if ((filePrefix == checksum) && (checksum != ""))
            {
                it = d->m_pmRefDownloadList.erase(it); // 修复列表中移除当前app/base/runtime
                std::cout << _("Repair") << ref.name << _("complete") << endl;
            }
            else
            {
                ++it; //迭代计算下一个文件
            }
        }
    }

    //如果得到的修复list为空说明不需要修复则直接返回
    if (d->m_pmRefDownloadList.empty())
    {
        for (const auto &name : vectorIds)
        {
            printf("Repair  %s complete", name.c_str());
        }
    }

    // 已损坏的应用进行修复,全卸掉
    for (auto &ref : d->m_pmRefDownloadList)
    {
        const auto &id = ref.ref.id; // 获取当前的 id

        if (!removeDeployFiles(id))
        {
            return KM_ERROR_DELETE_DIRECTORY_FAILED;
        }

        // 从本地 repo 中删除引用
        if (!deleteRefsFromRepo(id))
        {
            return KM_ERROR_DELETE_REF_TAG_FAILED;
        }
    }

    //清除下载
    d->m_pmDownloadRefs.clear();

    //  pull, deploy 对已经安装的不再安装
    for (auto &ref : d->m_pmRefDownloadList)
    {
        d->m_pmDownloadRefs.push_back(ref.completedRef);
    }

    // 下载包
    int pullFlag = false;
    pullFlag = ostreeManager.pull(REPO_NAME, d->m_pmDownloadRefs, progressCallback);

    // 部署包
    deploy(ostreeManager);
    for (const auto &name : vectorIds)
    {
        printf("Repair  %s complete", name.c_str());
    }
    return KM_ERROR_NO;
}

bool KMPackageManager::currentRefIsInstalled(KMPMRef &pmRef)
{
    KMInstalledAppQuery query;
    bool isInstalled = false;
    std::vector<KMRef> queryVector;
    string kindStr = pmRef.ref.kind.empty() ? "" : pmRef.ref.kind;
    string versionStr = pmRef.ref.version.empty() ? "" : pmRef.ref.version;
    string channelStr = pmRef.ref.channel.empty() ? "" : pmRef.ref.channel;
    string archStr = pmRef.ref.arch.empty() ? "" : pmRef.ref.arch;
    string moduleStr = pmRef.ref.module.empty() ? "binary" : pmRef.ref.module;

    queryVector = query.kind(kindStr).id(pmRef.ref.id).arch(archStr).channel(channelStr).version(versionStr).module(moduleStr).query(KMInstalledAppQuery::All);

    KMVersion installedVersion;
    KMVersion currentVersion;

    if (!queryVector.empty())
    {
        if (versionStr.empty())
        {
            // 未指定版本，则认为已安装
            isInstalled = true;
        }
        else
        {
            currentVersion = KMVersion::parse(versionStr, false);

            // 指定版本，则检查是否已安装
            for (const auto &ref : queryVector)
            {
                installedVersion = KMVersion::parse(ref.version, false);
                if (installedVersion == currentVersion)
                {
                    isInstalled = true;
                    break;
                }
            }
        }
    }
    return isInstalled;
}

bool KMPackageManager::currentRefVersionIsInstalled(KMPMRef &pmRef)
{
    KMInstalledAppQuery query;
    bool isInstalled = false;
    std::vector<KMRef> queryVector;
    string kindStr = pmRef.ref.kind.empty() ? "" : pmRef.ref.kind;
    string versionStr = pmRef.ref.version.empty() ? "" : pmRef.ref.version;
    string channelStr = pmRef.ref.channel.empty() ? "" : pmRef.ref.channel;
    string archStr = pmRef.ref.arch.empty() ? "" : pmRef.ref.arch;
    string moduleStr = pmRef.ref.module.empty() ? "binary" : pmRef.ref.module;

    queryVector = query.kind(kindStr).id(pmRef.ref.id).arch(archStr).channel(channelStr).version(versionStr).module(moduleStr).query(KMInstalledAppQuery::All);

    KMVersion installedVersion;
    KMVersion currentVersion;

    if (!queryVector.empty())
    {
        if (versionStr.empty())
        {
            // 未指定版本，则认为已安装
            // isInstalled = true;
        }
        else
        {
            currentVersion = KMVersion::parse(versionStr, false);

            // 指定版本，则检查是否已安装
            for (const auto &ref : queryVector)
            {
                installedVersion = KMVersion::parse(ref.version, false);
                if (installedVersion == currentVersion)
                {
                    isInstalled = true;
                    break;
                }
            }
        }
    }
    return isInstalled;
}

bool KMPackageManager::currentRefIsUninstalled(KMPMRef &pmRef)
{
    KMInstalledAppQuery query;
    bool isInstalled = false;
    // std::vector<KMRef> queryVector;
    string kindStr = pmRef.ref.kind.empty() ? "" : pmRef.ref.kind;
    string versionStr = "";
    // string versionStr = pmRef.ref.version.empty() ? "" : pmRef.ref.version;
    string channelStr = pmRef.ref.channel.empty() ? "" : pmRef.ref.channel;
    string moduleStr = pmRef.ref.module.empty() ? "" : pmRef.ref.module;
    string archStr = pmRef.ref.arch.empty() ? "" : pmRef.ref.arch;

    d->m_pmQueryVector = query.kind(kindStr).id(pmRef.ref.id).arch(archStr).channel(channelStr).version(versionStr).module(moduleStr).query(KMInstalledAppQuery::All);

    KMVersion installedVersion;
    KMVersion currentVersion;

    if (!d->m_pmQueryVector.empty())
    {
        if (versionStr.empty())
        {
            // 未指定版本，则认为已安装
            isInstalled = true;
        }
        else
        {
            currentVersion = KMVersion::parse(versionStr, false);

            // 指定版本，则检查是否已安装
            for (const auto &ref : d->m_pmQueryVector)
            {
                installedVersion = KMVersion::parse(ref.version, false);
                if (installedVersion == currentVersion)
                {
                    isInstalled = true;
                    break;
                }
            }
        }
    }
    return isInstalled;
}

bool KMPackageManager::currentFuzzyRefIsInstalled(KMPMRef &pmRef)
{
    KMInstalledAppQuery query;
    bool isInstalled = false;

    string kindStr = pmRef.ref.kind.empty() ? "" : pmRef.ref.kind;
    string versionStr = "";
    string channelStr = pmRef.ref.channel.empty() ? "" : pmRef.ref.channel;
    string moduleStr = pmRef.ref.module.empty() ? "binary" : pmRef.ref.module;
    string archStr = pmRef.ref.arch.empty() ? "" : pmRef.ref.arch;

    std::vector<KMRef> queryVector = query.kind(kindStr).id(pmRef.ref.id).arch(archStr).channel(channelStr).version(versionStr).module(moduleStr).query(KMInstalledAppQuery::All);

    KMVersion installedVersion;
    KMVersion currentVersion;

    if (!queryVector.empty())
    {

        currentVersion = KMVersion::parse(pmRef.ref.version, false);

        // 指定版本，则检查是否已安装
        for (const auto &ref : queryVector)
        {
            installedVersion = KMVersion::parse(ref.version, false);
            if (ref.kind == "base" || ref.kind == "runtime" || ref.kind == "depend")
            {
                if (installedVersion.getMajor() == currentVersion.getMajor())
                {
                    if (installedVersion.getMinor() == currentVersion.getMinor())
                    {
                        if (installedVersion.getPatch() == currentVersion.getPatch())
                        {
                            if (d->m_pmIsForceInstall)
                            {
                                string removeStr = ref.baseInstallDir + "/" + ref.channel + "/" + ref.arch + "/" + ref.kind + "/" + ref.id + "/" + ref.module + "/" + ref.version;
                                d->m_pmOldAVersion.push_back(removeStr);
                            }
                            else
                            {
                                int maxVersion = installedVersion.compare(currentVersion);
                                if (maxVersion == 0)
                                {
                                    isInstalled = true;
                                }
                                if (maxVersion == -1)
                                {
                                    string removeStr = ref.baseInstallDir + "/" + ref.channel + "/" + ref.arch + "/" + ref.kind + "/" + ref.id + "/" + ref.module + "/" + ref.version;
                                    d->m_pmOldAVersion.push_back(removeStr);
                                }
                                if (maxVersion == 1 && pmRef.ref.isSpecialVersion != true)
                                {
                                    isInstalled = true;
                                }
                            }
                            break;
                        }
                        else
                        {
                            if (installedVersion.getPatch() < currentVersion.getPatch())
                            {
                                string removeStr = ref.baseInstallDir + "/" + ref.channel + "/" + ref.arch + "/" + ref.kind + "/" + ref.id + "/" + ref.module + "/" + ref.version;
                                d->m_pmOldAVersion.push_back(removeStr);
                                continue;
                            }
                            if (installedVersion.getPatch() > currentVersion.getPatch() && pmRef.ref.isSpecialVersion != true)
                            {
                                isInstalled = true;
                            }
                        }
                    }
                    else if (installedVersion.getMinor() < currentVersion.getMinor())
                    {
                        string removeStr = ref.baseInstallDir + "/" + ref.channel + "/" + ref.arch + "/" + ref.kind + "/" + ref.id + "/" + ref.module + "/" + ref.version;
                        d->m_pmOldAVersion.push_back(removeStr);
                        continue;
                    }
                    else
                    {
                        if (pmRef.ref.isSpecialVersion != true)
                        {
                            isInstalled = true;
                        }
                    }
                }
            }
            else
            {
                if (installedVersion != currentVersion || d->m_pmIsForceInstall)
                {
                    string removeStr = ref.baseInstallDir + "/" + ref.channel + "/" + ref.arch + "/" + ref.kind + "/" + ref.id + "/" + ref.module + "/" + ref.version;
                    d->m_pmOldAVersion.push_back(removeStr);
                }
                else
                {
                    isInstalled = true;
                    break;
                }
            }
        }
    }
    return isInstalled;
}

int KMPackageManager::isInstalled(string name)
{
    kmlogger.debug("Check wait for installing app %s", name.c_str());

    KMPMRef pmRef = KMUtil::parseKMPMRef(name);

    if (currentRefIsInstalled(pmRef))
    {
        kmlogger.info("%s is installed", name.c_str());
        return KM_ERROR_NO;
    }

    return KM_ERROR_NOT_INSTALLED;
}

int KMPackageManager::isUpgradabled(string name)
{
    kmlogger.debug("Check wait for update app %s", name.c_str());

    KMPMRef pmRef = KMUtil::parseKMPMRef(name);

    // 不安装,则不更新
    if (!currentRefIsInstalled(pmRef))
    {
        kmlogger.info("%s is not installed", name.c_str());
        return KM_ERROR_NOT_INSTALLED;
    }

    kmlogger.info("开始在远程仓库中查找 ref 对应的最新 commitid ...");
    // 下载和解析清单依赖文件 summary.json
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo

    KMOSTreeHandler ostreeManager(repoPath.string());

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);

    std::string summaryUrl = ostreeRepoUrl.append("/").append("summary.json");

    int getSummaryState = getRemoteSummary(summaryUrl, false);
    if (getSummaryState != KM_ERROR_NO)
    {
        kmlogger.error("Get and parse summary.json file error!");
        return getSummaryState;
    }

    // 从远程依赖文件查找对应的包是否存在，并获取所有的依赖列表
    bool isMatchedRefFlag = false;
    isMatchedRefFlag = d->m_parseSummaryJson->fuzzyMatchCompletedRef(pmRef, d->m_pmFuzzyMatchRefs);
    if (!isMatchedRefFlag)
    {
        std::cout << _("Not find this online ref ") << name << std::endl;
        return KM_ERROR_REF_NOT_FOUND;
    }

    for (const auto &ref : d->m_pmFuzzyMatchRefs)
    {
        kmlogger.debug("%s", ref.c_str());
    }

    // 依赖列表去重
    KMUtil::removeDuplicateValues(d->m_pmFuzzyMatchRefs);

    vector<string> pmMatchRefs;
    for (const auto &ref : d->m_pmFuzzyMatchRefs)
    {
        if (KMStringUtils::contains(ref, pmRef.ref.id))
        {
            pmMatchRefs.push_back(ref);
        }
    }

    // only one : "stable/x86_64/app/top.openkylin.Music/binary/2.0.1.0"
    for (const auto &ref : pmMatchRefs)
    {
        KMPMRef pmUpdateRef = KMUtil::parseSummaryFuzzyKMPMRef(ref);

        kmlogger.debug("%s", ref.c_str());

        if (!currentRefIsInstalled(pmUpdateRef))
        {
            kmlogger.info("need update %s", ref.c_str());
            return KM_ERROR_NO;
        }
    }

    printf("%s\n", _("This app not need update!"));
    return KM_ERROR_NOT_NEED_UPDATE;
}

int KMPackageManager::getRemoteSummary(const string &summaryUrl, bool isExpired)
{
    fs::path basePath = d->m_folder->getPath();
    fs::path summaryJsonPath = basePath / "summary.json";

    kmlogger.debug("Begin to curl %s", summaryUrl.c_str());
    if (fs::exists(summaryJsonPath))
    {
        kmlogger.info("summary.json is exists");

        if (!isExpired)
        {
            // 依赖文件清单未过期并且存在
            kmlogger.info("summary.json is not expired or not need update");

            if (!d->m_util->isJsonFile(summaryJsonPath.string()))
            {
                kmlogger.error("summary.json is not a valid json file, please check repo config url value is correct.");
                if (!KMCurl::curlApiDownload(summaryUrl, summaryJsonPath.string()))
                {
                    kmlogger.error("Curl download failed. SummaryUrl:  %s  Store summary.json to SummaryIdxPath: %s", summaryUrl.c_str(), summaryJsonPath.string().c_str());

                    std::cout << _("Please check your network connection!") << std::endl;

                    return KM_ERROR_CURL_DOWNLOAD_FAILED;
                }
            }
        }
        else
        {
            // 依赖文件清单过期，需要更新 summary.json
            kmlogger.info("summary.json is expired, need update");

            if (!KMCurl::curlApiDownload(summaryUrl, summaryJsonPath.string()))
            {
                kmlogger.error("Curl download failed. SummaryUrl:  %s  Store summary.json to SummaryIdxPath: %s", summaryUrl.c_str(), summaryJsonPath.string().c_str());

                std::cout << _("Please check your network connection!") << std::endl;

                return KM_ERROR_CURL_DOWNLOAD_FAILED;
            }
        }
    }
    else
    {
        fs::create_directories(basePath);
        // 依赖文件清单不存在，需要下载
        if (!KMCurl::curlApiDownload(summaryUrl, summaryJsonPath.string()))
        {
            kmlogger.error("Curl download failed. SummaryUrl:  %s  Store summary.json to SummaryIdxPath: %s", summaryUrl.c_str(), summaryJsonPath.string().c_str());

            std::cout << _("Please check your network connection!") << std::endl;

            return KM_ERROR_CURL_DOWNLOAD_FAILED;
        }
    }

    if (!d->m_util->isJsonFile(summaryJsonPath.string()))
    {
        kmlogger.error("summary.json is not a valid json file, please check repo config url value is correct.");
        std::cout << _("summary.json is not a valid json file, please check repo config url value is correct.") << std::endl;
        return KM_ERROR_SUMMARY_JSON_INVALID;
    }

    d->m_parseSummaryJson->loadFile(summaryJsonPath.string());
    d->m_parseSummaryJson->printJson();
    d->m_parseSummaryJson->parseSummaryJson();
    // 生成 /opt/kaiming/packages
    d->m_parseSummaryJson->getPackagesFromSummary();

    return KM_ERROR_NO;
}

int KMPackageManager::getAllFuzzyMatchRefVector(const vector<string> &vectorIds, PackageManagerOptions pmOptions, TaskType taskType)
{
    for (const auto &name : vectorIds)
    {
        kmlogger.debug("Install app %s", name.c_str());
        bool isMatchedRefFlag = false;

        KMPMRef pmRef = d->m_util->parseKMPMRef(name);
        d->m_util->printKMPMRef(name, pmRef);

        // 如果用户指定了 arch，则覆盖默认的 arch
        if (!pmOptions.arch.empty())
        {
            pmRef.ref.arch = pmOptions.arch;
        }

        if (!pmOptions.kind.empty())
        {
            pmRef.ref.kind = pmOptions.kind;
        }

        if (!pmRef.ref.version.empty())
        {
            pmRef.ref.isSpecialVersion = true;
            d->m_pmSpecialIdVersion.push_back(pmRef.ref.id + pmRef.ref.version);
        }

        switch (taskType)
        {
        case TASK_TYPE_INSTALL:
            // 已安装当前软件包或指定版本包则不再安装
            if (currentRefVersionIsInstalled(pmRef))
            {
                if (!pmOptions.force)
                {
                    return KM_ERROR_FORCE_INSTALL;
                }
                kmlogger.info("当前软件包 %s 已安装", name.c_str());
                continue;
            }

            break;
        case TASK_TYPE_UPDATE:
            // 未安装该包或该包指定版本,则不更新，直接返回
            if (!currentRefIsUninstalled(pmRef))
            {
                if (pmRef.ref.version.empty())
                {
                    kmlogger.info("未安装该软件包 %s", name.c_str());
                    std::cout << _("Not install this ref ") << name << std::endl;
                    return KM_ERROR_REF_NOT_INSTALLED;
                }
            }
            break;
        case TASK_TYPE_UNINSTALL:
            // 未安装该包或该包指定版本,则不更新，直接返回
            if (!currentRefIsUninstalled(pmRef))
            {
                kmlogger.error("%s not installed!", name.c_str());
                printf("%s not installed!", name.c_str());
                return KM_ERROR_REF_NOT_INSTALLED;
            }
            break;
        case TASK_TYPE_REPAIR:
            // 未安装该包或该包指定版本,则不修复，直接返回
            if (!currentRefIsUninstalled(pmRef))
            {
                kmlogger.error("%s not installed!", name.c_str());
                printf("%s not installed!", name.c_str());
                return KM_ERROR_REF_NOT_INSTALLED;
            }
            break;
        default:
            break;
        }

        // 从远程依赖文件查找对应的包是否存在，并获取所有的依赖列表
        isMatchedRefFlag = d->m_parseSummaryJson->fuzzyMatchCompletedRef(pmRef, d->m_pmFuzzyMatchRefs);

        if (!isMatchedRefFlag)
        {
            std::cout << _("Not find this online ref ") << name << std::endl;
            return KM_ERROR_REF_NOT_FOUND;
        }

        for (const auto &ref : d->m_pmFuzzyMatchRefs)
        {
            kmlogger.debug("%s", ref.c_str());
        }
        // 依赖列表去重
        KMUtil::removeDuplicateValues(d->m_pmFuzzyMatchRefs);
    }

    return KM_ERROR_NO;
}

int KMPackageManager::getAllFuzzyMatchOKRefVector(const vector<string> &vectorIds, PackageManagerOptions pmOptions, TaskType taskType)
{
    return 0;
}

void KMPackageManager::getUsefulRefList()
{
    string preRef;
    for (auto it = d->m_pmFuzzyMatchRefs.begin(); it != d->m_pmFuzzyMatchRefs.end(); it++)
    {
        string ref = *it;
        if (preRef.empty())
        {
            preRef = ref;
            continue;
        }
        else
        {
            KMPMRef pmFuzzyRef = KMUtil::parseSummaryFuzzyKMPMRef(ref);
            KMPMRef pmPreRef = KMUtil::parseSummaryFuzzyKMPMRef(preRef);
            if (pmFuzzyRef.ref.id == pmPreRef.ref.id && pmFuzzyRef.ref.kind == pmPreRef.ref.kind && pmFuzzyRef.ref.module == pmPreRef.ref.module && pmFuzzyRef.ref.arch == pmPreRef.ref.arch && pmFuzzyRef.ref.channel == pmPreRef.ref.channel)
            {
                if (pmFuzzyRef.ref.kind == "app")
                {
                    if (KMVersion::parse(pmFuzzyRef.ref.version) > KMVersion::parse(pmPreRef.ref.version))
                    {
                        auto findFuzzyIt = std::find(d->m_pmFuzzyMatchRefs.begin(), d->m_pmFuzzyMatchRefs.end(), preRef);
                        if (findFuzzyIt != d->m_pmFuzzyMatchRefs.end())
                        {
                            it = d->m_pmFuzzyMatchRefs.erase(findFuzzyIt);
                        }
                        preRef = ref;
                        continue;
                    }
                }
                else
                {
                    std::istringstream currentVersion(pmFuzzyRef.ref.version);
                    std::istringstream preVersion(pmPreRef.ref.version);
                    int major, minor, patch, secure;
                    int preMajor, preMinor, prePatch, preSecure;
                    char dot;
                    currentVersion >> major >> dot >> minor >> dot >> patch;
                    preVersion >> preMajor >> dot >> preMinor >> dot >> prePatch;
                    if (major != preMajor || minor != preMinor)
                    {
                        preRef = ref;
                        continue;
                    }
                    else
                    {
                        if (patch >= prePatch)
                        {
                            auto findFuzzyIt = std::find(d->m_pmFuzzyMatchRefs.begin(), d->m_pmFuzzyMatchRefs.end(), preRef);
                            if (findFuzzyIt != d->m_pmFuzzyMatchRefs.end())
                            {
                                std::string idVersion = pmPreRef.ref.id + pmPreRef.ref.version;
                                auto idVersionIt = std::find(d->m_pmSpecialIdVersion.begin(), d->m_pmSpecialIdVersion.end(), idVersion);
                                if (idVersionIt == d->m_pmSpecialIdVersion.end())
                                {
                                    it = d->m_pmFuzzyMatchRefs.erase(findFuzzyIt);
                                }
                            }
                            preRef = ref;
                            continue;
                        }
                    }
                }
            }
            else
            {
                preRef = ref;
            }
        }
    }
    return;
}

void KMPackageManager::getDownloadRefList(TaskType taskType)
{
    for (auto &ref : d->m_pmFuzzyMatchRefs)
    {
        KMPMRef pmFuzzyRef = KMUtil::parseSummaryFuzzyKMPMRef(ref);
        switch (taskType)
        {
        case TASK_TYPE_INSTALL:
            // 安装时，过滤掉已安装的软件
            if (currentFuzzyRefIsInstalled(pmFuzzyRef))
            {
                std::string idVersion = pmFuzzyRef.ref.id + pmFuzzyRef.ref.version;
                auto it = std::find(d->m_pmSpecialIdVersion.begin(), d->m_pmSpecialIdVersion.end(), idVersion);
                if (it == d->m_pmSpecialIdVersion.end())
                {
                    continue;
                }
            }
            break;
        case TASK_TYPE_UPDATE:
            // 更新时也是过滤掉已安装的软件
            if (currentFuzzyRefIsInstalled(pmFuzzyRef))
            {
                continue;
            }
            break;
        case TASK_TYPE_REPAIR:
            // 修复时不过滤掉已安装的软件
            if (!currentFuzzyRefIsInstalled(pmFuzzyRef))
            {
                KMPMRef pmRef = pmFuzzyRef;
                pmRef.ref.version = "";
                if (!currentRefIsInstalled(pmRef))
                {
                    continue;
                }
            }
            break;
        default:
            break;
        }

        kmlogger.debug("Installing ref : %s", ref.c_str());

        // 再次构建完整的 ostree ref
        pmFuzzyRef.completedRef = KMUtil::dupKMPMCompletedRef(pmFuzzyRef);
        // d->m_pmDownloadRefs.clear();
        d->m_pmDownloadRefs.push_back(pmFuzzyRef.completedRef);
        d->m_parseSummaryJson->getSummaryInfo(pmFuzzyRef);

        d->m_pmRefDownloadList.push_back(pmFuzzyRef);
        globalRefDownloadListForProgress.push_back(pmFuzzyRef);
    }
}
void KMPackageManager::printUninstallDependsOnList()
{
    d->m_formatter->setColumnWidth(35, 35, 15, 10, 25, 25, 30, 25, 35, 35);
    d->m_formatter->setShowArch(false);
    d->m_formatter->setShowChannel(true);
    d->m_formatter->printHeader();

    bool foundAnyEntries = false;
    for (auto &uninstallIt : d->m_pmUninstallVector)
    {
        std::string findStr = uninstallIt.channel + ":" + uninstallIt.id + "/" + uninstallIt.version[0];
        bool foundAny = false;

        for (auto &pair : m_infoMap)
        {
            KMInfoJson &info = pair.second;
            bool kindMatch = info[uninstallIt.kind].find(findStr) != std::string::npos;
            bool archMatch = info[uninstallIt.kind].find(uninstallIt.arch) != std::string::npos;
            bool moduleMatch = info.module == uninstallIt.module;

            if (kindMatch && archMatch && moduleMatch)
            {
                foundAnyEntries = true;

                string installedSize = KMUtil::formatInstalledSize((double)info.size);
                KMEntry entry;
                entry.id = info.id;
                entry.name = info.name;
                entry.description = info.description;
                entry.module = info.module;
                entry.version = info.version;
                entry.arch = info.archs.front();
                entry.channel = info.channel;
                entry.size = installedSize;

                d->m_formatter->printEntry(entry);
            }
        }
    }

    d->m_formatter->printFooter();

    if (!foundAnyEntries)
    {
        std::cout << "No matching packages found for uninstallation.\n";
    }
}

void KMPackageManager::printDownloadRefList(const vector<KMPMRef> &downloadRefs)
{
    d->m_formatter->setColumnWidth(35, 35, 15, 10, 25, 25, 30, 25, 35, 35);
    d->m_formatter->setShowArch(false);
    d->m_formatter->setShowChannel(true);
    d->m_formatter->printHeader();

    for (const auto &pmRef : downloadRefs)
    {
        string installedSize = KMUtil::formatInstalledSize((double)pmRef.installedSize);

        KMEntry entry;
        entry.id = pmRef.ref.id;
        entry.name = pmRef.name;
        entry.description = pmRef.description;
        entry.module = pmRef.ref.module;
        entry.version = pmRef.ref.version;
        entry.arch = pmRef.ref.arch;
        entry.channel = pmRef.ref.channel;
        entry.size = installedSize;

        d->m_formatter->printEntry(entry);
    }

    d->m_formatter->printFooter();
}

bool KMPackageManager::printAssumeYesChoice(PackageManagerOptions pmOptions)
{
    if (!pmOptions.assumeYes)
    {
        std::cout << _("Do you want to install these changes? [Y/n]: ");

        char yesOption;

        while (true)
        {
            yesOption = std::cin.get();

            // 检查是否遇到 EOF(Ctrl+D)
            if (std::cin.eof())
            {
                std::cout << _("\nInput ended unexpectedly. Cancel install.\n");
                return false;
            }

            if (d->m_util->isYes(yesOption))
            {
                break;
            }
            else if (d->m_util->isNo(yesOption))
            {
                std::cout << _("Cancel install.\n");
                return false;
            }
            else
            {
                std::cout << _("Do you want to install these changes? [Y/n]: ");
            }
        }
    }

    return true;
}

int KMPackageManager::getTerminalWidth()
{
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
    return w.ws_col;
}

/**
 * @brief 进度处理回调函数
 *
 * 进度条处理分成3个步骤：
 *  - 1. 当拉取 metadata 时， 增长到 5%;
 *  - 2. 下载数据一直到 97%;
 *  - 3. 写入 ostree objects 为最后的 3%
 *
 * @param progressStatus 在 ostree pull 时，发送的进度等信息结构体
 */
void KMPackageManager::progressCallback(ProgressStatus progressStatus)
{
    kmlogger.debug("enter installProgressCallback, current ref: %s", progressStatus.ref.c_str());
    char buf[1024 * 8];
    guint64 total = 0;
    guint64 elapsedTime;
    guint newProgress = 0;
    gboolean estimating = false;
    guint64 totalTransferred;
    gboolean lastWasMetadata = progressStatus.lastWasMetadata;
    gchar *formattedBytesTotalTransferred = NULL;

    int i;
    int fullSize, partial;
    char *speed = NULL;
    int barLength;
    const char *partialBlocks[] = {" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"};
    const char *fullBlock = "█";

    int rows = 24, cols = 80;

    elapsedTime = (g_get_monotonic_time() - progressStatus.startTime) / G_USEC_PER_SEC;
    kmlogger.debug("elapsedTime: %ld", elapsedTime);

    if (*progressStatus.ostreeStatus)
    {
        // 当ostree_status 有反馈，则代表fetch成功，总进度到了100%
        kmlogger.debug("install ostree status receive pull success");
        newProgress = 100;
        progressStatus.progress = 100;
    }
    else
    {
        totalTransferred = progressStatus.bytesTransferred + progressStatus.transferredExtraDataBytes;
        formattedBytesTotalTransferred = g_format_size_full(totalTransferred, G_FORMAT_SIZE_IEC_UNITS);

        progressStatus.lastWasMetadata = false;

        if (progressStatus.totalDeltaParts == 0 && (progressStatus.outstandingMetadataFetches > 0 || lastWasMetadata) && progressStatus.metadataFetched < 20)
        {
            /* 在没有完成 metadata 处理时，我们需要执行2次回调函数，
                    因为有时会遇到仅处理元数据会触发调用，但却没进行处理和添加更多元数据。*/
            if (progressStatus.outstandingMetadataFetches > 0)
            {
                progressStatus.lastWasMetadata = true;
            }

            /* At this point we don't really know how much data there is, so we have to make a
             * guess. Since its really hard to figure out early how much data there is we report 1%
             * until all objects are scanned. */

            estimating = true;

            sprintf(buf, _("Downloading metadata: %u/(estimating) %s"), progressStatus.fetched, formattedBytesTotalTransferred);
            kmlogger.debug("Downloading metadata buf: %s", buf);

            /* 增长到 5% 直到所有元数据都被拉取了 */
            newProgress = 0;
            if (progressStatus.requested > 0)
            {
                newProgress = progressStatus.fetched * 5 / progressStatus.requested;
            }
        }
        else
        {
            if (progressStatus.totalDeltaParts > 0)
            {
                gchar *formattedBytesTotal = NULL;

                /* 仅仅使用 deltas, 因此我们可以忽略 regular objects 来获得更好的 sizes;
                 *
                 * fetchedDeltaPartSize 所有 delta 部分 和 fallback objects 参数的总大小，
                 * 它是在最开始可以获得的，因此不用下载。
                 */
                total = progressStatus.totalDeltaPartSize - progressStatus.fetchedDeltaPartSize + progressStatus.totalExtraDataBytes;
                formattedBytesTotal = g_format_size_full(total, G_FORMAT_SIZE_IEC_UNITS);

                sprintf(buf, _("Downloading: %s/%s"), formattedBytesTotalTransferred, formattedBytesTotal);
                kmlogger.debug("Downloading buf: %s", buf);
            }
            else
            {
                /* Non-deltas, 因此我们不能知道除了 object 计数和额外数据的字节大小以外的任何东西，
                       为了比较它们和额外数据，我们使用平均对象大小来评估总大小。*/
                double averageObjectSize = 1;
                if (progressStatus.fetched > 0)
                {
                    averageObjectSize = progressStatus.bytesTransferred / (double)progressStatus.fetched;
                }

                total = averageObjectSize * progressStatus.requested + progressStatus.totalExtraDataBytes;

                gchar *formattedBytesTotal = g_format_size_full(total, G_FORMAT_SIZE_IEC_UNITS);
                sprintf(buf, _("Downloading extra data: %s/%s"), formattedBytesTotalTransferred, formattedBytesTotal);
                kmlogger.debug("下载额外数据 buf: %s", buf);

                sprintf(buf, _("Downloading files: %d/%d %s"), progressStatus.fetched, progressStatus.requested, formattedBytesTotalTransferred);
                kmlogger.debug("下载文件: %s", buf);
            }

            /* 下载总进度到达 97% */
            if (total > 0)
            {
                newProgress = 5 + ((totalTransferred / (gdouble)total) * 92); // 这个数据会因下载额外数据导致不准，比如会从 75 降到 48
            }
            else
            {
                newProgress = 97;
            }

            /* 增加最后写入对象的 3% 进度 */
            newProgress += getWriteProgress(progressStatus.outstandingWrites);
        }

        if (elapsedTime > 0) // Ignore first second
        {
            gchar *formattedBytesSec = g_format_size(totalTransferred / elapsedTime);
            sprintf(buf, " (%s/s)", formattedBytesSec);
            kmlogger.debug("totalTransferred: %ld elapsedTime: %ld buf: %s", totalTransferred, elapsedTime, buf);
        }
    }

    kmlogger.info("newProgress: %d currentPercent: %d", newProgress, currentPercent);
    // 当进度小于当前进度时，更新进度
    if (newProgress < currentPercent)
    {
        newProgress = currentPercent;
    }
    else
    {
        if (newProgress == 100)
        {
            currentPercent = 0;
        }
        else
        {
            currentPercent = newProgress;
        }
    }

    progressStatus.lastTotal = total;
    kmlogger.debug("newProgress: %d\n", newProgress);
    if (newProgress > 100)
    {
        if (!progressStatus.reportedOverflow)
        {
            kmlogger.error("Unexpectedly got > 100%% progress, limiting");
        }

        progressStatus.reportedOverflow = true;
        newProgress = 100;
    }

    guint singlePercent = newProgress; // 单一软件包下载进度，这个单一进度会因下载额外数据导致不准，比如会从 75 降到 48

    string currentRefId;

    uint64_t totalSize = getTotalSize();
    uint64_t singleSize = getSingleSize(progressStatus.ref, currentRefId);

    guint totalPercent = 0;    // 总进度
    guint currentProgress = 0; // 当前的进度
    string lastDownloadRef = globalRefDownloadListForProgress.back().completedRef;
    kmlogger.debug("lastDownloadRef: %s", lastDownloadRef.c_str());

    for (const auto &item : globalRefDownloadListForProgress) // 内部排序，因此不能顺序存储
    {
        kmlogger.debug("completedRef: %s size:%ld ", item.completedRef.c_str(), item.installedSize);
        // 当前下载的 ref 进度
        if (item.completedRef == progressStatus.ref)
        {
            currentProgress += (double)singlePercent / 100 * singleSize;
            break;
        }
        currentProgress += item.installedSize;
    }

    totalPercent = (double)currentProgress * 100 / totalSize;

    kmlogger.info("singlePercent:%d singleSize: %ld currentProgress: %ld  totalSize: %ld totalPercent: %d", singlePercent, singleSize, currentProgress, totalSize, totalPercent);

    progressStatus.progress = totalPercent;

    progressStatus.estimating = estimating;
    int speed_len = 0;

    if (elapsedTime > 0)
    {
        char *formattedBytesSec = g_format_size(totalTransferred / elapsedTime);
        string remaining;
        if (elapsedTime > 3 && singlePercent > 0)
        {
            guint64 totalTime = elapsedTime * 100 / (double)singlePercent;
            remaining = formatDuration(totalTime - elapsedTime);
            kmlogger.debug("totalTime:%ld elapsedTime:%ld  remaining_time:%ld remaining: %s", totalTime, elapsedTime, totalTime - elapsedTime, remaining.c_str());
        }

        guint64 remainingBytes = totalSize - currentProgress;
        string remainingStr = calculateDownloadTime(string(formattedBytesSec), remainingBytes);
        kmlogger.debug("remainingBytes: %ld remainingStr: %s preRemaining:%s", remainingBytes, remainingStr.c_str(), preRemaining.c_str());

        preRemaining = (remainingStr != "") ? remainingStr : preRemaining;
        // speed = g_strdup_printf("%s", formattedBytesSec);
        speed = g_strdup_printf("%s/s %s", formattedBytesSec, preRemaining.c_str());
        speed_len = MAX(speed_len, strlen(speed) + 2);
    }

    barLength = 40;
    fullSize = (barLength * totalPercent) / 100;
    partial = (((barLength * totalPercent) % 100) * G_N_ELEMENTS(partialBlocks)) / 100;

    char str[1024 * 8];
    sprintf(str, "%s %-20s ", "正在安装 ", currentRefId.c_str());

    kmlogger.debug("fullSize: %d barLength:%d", fullSize, barLength);
    for (i = 0; i < fullSize; i++)
    {
        sprintf(str + strlen(str), "%s", fullBlock);
    }

    if (i < barLength)
    {
        sprintf(str + strlen(str), "%-20s", partialBlocks[partial]);
        kmlogger.debug("str: %s", str);
        i++;
    }

    sprintf(str + strlen(str), " %d%s", totalPercent, "%");

    if (*progressStatus.ostreeStatus)
    {
        // printf("\n");

        if (elapsedTime > 0)
        {
            char *formattedBytesSec = g_format_size(totalTransferred / elapsedTime);
            speed = g_strdup_printf("%s/s %s", formattedBytesSec, preRemaining.c_str());

            guint64 remainingBytes = totalSize - currentProgress;
            string remainingStr = calculateDownloadTime(string(formattedBytesSec), remainingBytes).c_str();
            kmlogger.debug("remainingBytes: %ld remainingStr: %s preRemaining:%s", remainingBytes, remainingStr.c_str(), preRemaining.c_str());

            preRemaining = (remainingStr != "") ? remainingStr : preRemaining;
            speed = g_strdup_printf("%s/s %s", formattedBytesSec, preRemaining.c_str());
            speed_len = MAX(speed_len, strlen(speed) + 2);
        }
        else
        {
            // elapsedTime: 0
            kmlogger.debug("elapsedTime == 0");
            speed = g_strdup_printf("%s/s %s", "5 MB", "03:30");
            speed_len = MAX(speed_len, strlen(speed) + 2);
        }
        if (speed)
        {
            sprintf(str + strlen(str), " %s", speed);
        }
    }
    else
    {
        if (speed)
        {
            sprintf(str + strlen(str), " %s", speed);
        }
    }

    bool hasWrapped = false; // 标记输出字符是否已换行
    int terminalWidth = getTerminalWidth();

    // 处理换行及显示更新
    if (strlen(str) > terminalWidth)
    { // 输出字符大于当前终端宽度，则已经换行
        hasWrapped = true;
        std::cout << "\r" << str << std::endl;
    }
    else
    {
        if (hasWrapped == true)
        {
            // 之前进度条发生过换行，则需要清除之前换行产生的多余显示
            std::cout << "\r"; // 输出回车符，将光标移动到行首
            for (int i = 0; i < terminalWidth; ++i)
            {
                std::cout << " ";
            }
            std::cout << "\r";
            hasWrapped = false;
        }
        //输出回车符，将光标移到行首，并左对齐
        std::cout << "\r" << std::left << std::setw(terminalWidth) << str;
        std::cout.flush(); //刷新输出缓冲区
    }

    lastOutput = string(str);

    kmlogger.debug("currentRef: %s lastRef: %s progress", progressStatus.ref.c_str(), progressStatus.lastRef.c_str());
    if (progressStatus.ref == progressStatus.lastRef && *progressStatus.ostreeStatus)
    {
        totalPercent = 100;
        printf("\n"); // 最后输出需要换行
    }

    if (speed)
    {
        kmlogger.debug("speed: %s", speed);
    }
    else
    {
        speed = g_strdup_printf("5 MB/s 03:30");
        speed_len = MAX(speed_len, strlen(speed) + 2);
    }

    globalProgressStatus.speed = string(speed); // todo: 存在段错误
    globalProgressStatus.refId = currentRefId;
    globalProgressStatus.progress = totalPercent;
    globalProgressStatus.timeout = 5;

    kmlogger.debug("install progress------>>:  refId:%s progress:%d speed:%s timeout:%d", globalProgressStatus.refId.c_str(), globalProgressStatus.progress, globalProgressStatus.speed.c_str(), globalProgressStatus.timeout);

    progressJson = KMDbusJson::packProgressInfoToJson(globalProgressStatus.refId, globalProgressStatus.progress, globalProgressStatus.speed, globalProgressStatus.timeout);

    updateProgress();

    fflush(stdout); // 刷新输出缓冲区
}

int KMPackageManager::getWriteProgress(int outstandingWrites)
{
    return outstandingWrites > 0 ? (int)(3 / (double)outstandingWrites) : 3;
}

uint64_t KMPackageManager::getTotalSize()
{
    uint64_t sumSize = 0;
    for (const auto &ref : globalRefDownloadListForProgress)
    {
        kmlogger.debug("completedRef: %s installedSize:%ld", ref.completedRef.c_str(), ref.installedSize);

        sumSize += ref.installedSize;
    }

    return sumSize;
}

uint64_t KMPackageManager::getSingleSize(string completedRef, string &id)
{
    uint64_t singleSize;
    for (const auto &pmRef : globalRefDownloadListForProgress)
    {
        kmlogger.debug("completedRef: %s installedSize:%ld", pmRef.completedRef.c_str(), pmRef.installedSize);
        if (completedRef == pmRef.completedRef)
        {
            singleSize = pmRef.installedSize;
            id = pmRef.ref.id;
        }
    }

    return singleSize;
}

void KMPackageManager::updateProgress()
{
    // 只有当 globalProgressCallback
    // 是有效的时候才调用,即已经与某个可调用对象关联，并且没有被释放，避免 bad_function_call
    if (globalProgressCallback && progressJson != "")
    {
        globalProgressCallback(progressJson);
    }
}

string KMPackageManager::formatDuration(guint64 duration)
{
    int h, m, s;

    std::stringstream ss;

    m = duration / 60;
    s = duration % 60;
    h = m / 60;
    m = m % 60;

    if (h > 0)
    {
        // 使用流操作符进行格式化，输出为两位数
        ss.fill('0'); // 填充字符为 '0'
        ss.width(2);  // 设置宽度为 2
        ss << h << ":";
    }

    ss.fill('0');
    ss.width(2);
    ss << m << ":";

    ss.fill('0');
    ss.width(2);
    ss << s;

    return ss.str();
}

std::string KMPackageManager::calculateDownloadTime(const std::string &speed, guint64 sizeBytes)
{
    long int downloadSpeed;
    std::string result;

    kmlogger.debug("speed: %s sizeBytes: %ld", speed.c_str(), sizeBytes);

    // Parse the speed string to get the download speed in bytes/s
    if (speed.find("MB") != std::string::npos)
    {
        downloadSpeed = std::stol(speed.substr(0, speed.find("MB") - 1)) * 1024 * 1024; // Convert MB/s to bytes/s
    }
    else if (speed.find("kB") != std::string::npos)
    {
        downloadSpeed = std::stol(speed.substr(0, speed.find("kB") - 1)) * 1024; // Convert kB/s to bytes/s
    }
    else if (speed.find("bytes") != std::string::npos)
    {
        downloadSpeed = std::stol(speed.substr(0, speed.find("bytes") - 1));
        if (downloadSpeed == 0)
        {
            downloadSpeed = 5 * 1024; // 当 speed 属于 0 bytes/s 时，代表不下载，但进度也应该有，因此默认为5*1024
                                      // = 5KB 计算时间
        }
    }
    else
    {
        if (sizeBytes < 169887)
        {
            return "00:10"; // 给出默认时间 10 秒
        }
        else
        {
            return "01:00"; // 给出默认时间 1 分钟
        }
    }
    kmlogger.debug("speed: %s sizeBytes: %ld downloadSpeed=%ld", speed.c_str(), sizeBytes, downloadSpeed);

    // if (isZero(downloadSpeed))
    if (downloadSpeed == 0 && sizeBytes > 0)
    {
        // return "";
        downloadSpeed = 5 * 1024; // 当 speed 属于 0 bytes/s 时，代表不下载，但进度也应该有，因此默认为50计算时间
    }

    // Calculate the remaining download time in seconds
    int downloadTime = (int)sizeBytes / downloadSpeed;
    kmlogger.debug("speed: %s sizeBytes: %ld downloadSpeed=%ld downloadTime=%d", speed.c_str(), sizeBytes, downloadSpeed, downloadTime);

    // Format the download time as hours:minutes:seconds or minutes:seconds
    if (downloadTime >= 3600)
    {
        int hours = static_cast<int>(downloadTime / 3600);
        int minutes = static_cast<int>((downloadTime % 3600) / 60);
        int seconds = static_cast<int>(downloadTime % 60);
        result = std::to_string(hours) + ":" + std::to_string(minutes) + ":" + std::to_string(seconds);
        kmlogger.debug("speed: %s sizeBytes: %ld downloadSpeed=%ld downloadTime=%d result:%s", speed.c_str(), sizeBytes, downloadSpeed, downloadTime, result.c_str());
    }
    else
    {
        int minutes = static_cast<int>(downloadTime / 60);
        int seconds = static_cast<int>(downloadTime % 60);
        result = std::to_string(minutes) + ":" + std::to_string(seconds);
        kmlogger.debug("speed: %s sizeBytes: %ld downloadSpeed=%ld downloadTime=%d result:%s", speed.c_str(), sizeBytes, downloadSpeed, downloadTime, result.c_str());
    }

    if (result.find("-") != std::string::npos)
    {
        // 时间为负数不合理，此处先默认给出5分钟
        return "05:00";
    }

    return result;
}

int KMPackageManager::deploy(KMOSTreeHandler &ostreeManager)
{
    fs::path basePath = d->m_folder->getPath();
    fs::path layersPath = basePath / "layers";

    kmlogger.info("部署开始");
    for (auto &downloadRef : d->m_pmRefDownloadList)
    {
        d->m_installedFiles.clear();
        if (downloadRef.ref.module == "devel")
        {
            layersPath = fs::path(KMStorageDir::getUserBaseDirLocation());
        }
        kmlogger.info("completedRef: %s", downloadRef.completedRef.c_str());

        fs::path idPath = layersPath / downloadRef.ref.channel / downloadRef.ref.arch / downloadRef.ref.kind / downloadRef.ref.id;

        fs::path versionDataPath = layersPath / downloadRef.completedRef;
        kmlogger.debug("versionDataPath:  %s", versionDataPath.c_str());
        // d->m_installedFiles.insert(idPath.string());
        d->m_installedFiles.insert(versionDataPath.string());

        if (std::filesystem::exists(versionDataPath) || std::filesystem::create_directories(versionDataPath))
        {
            kmlogger.debug("Directory created or already exists successfully!");
        }

        // ostreeManager.checkout("f3b1314b51f2b8865089f13cbae5b7cd449b169f0b36530d27da74beb68aa492", "your-repo-path");
        kmlogger.debug("Begin to checkout ...");
        string latestCommit = ostreeManager.readLatestCommit(downloadRef.completedRef);
        ostreeManager.checkout(latestCommit, versionDataPath.string());
        kmlogger.debug("End to checkout.");

        // add "active/files/.ref" => content ""
        fs::path emptyFileRef = versionDataPath / "files/.ref";
        createFileForEmptyString(emptyFileRef.string());

        kmlogger.info("baseType:  %s", downloadRef.ref.kind.c_str());
        d->m_hostAppDepoy->setHostAppConfig(versionDataPath, downloadRef.ref.id);
        if (d->m_hostAppDepoy->loadHostAppInfo())
        {
            d->m_hostAppDepoy->collectSynchronizedFiles();
            if (currentRefIsUninstalled(downloadRef))
            {
                KMInfo("ok already installed!");
            }
            else
            {
                KMInfo("ok not installed!");
                if (d->m_hostAppDepoy->checkFileConflicts())
                {
                    KMError("uninstall conflicting software packages first!");
                    d->m_okFile->umountOK();
                    return KM_ERROR_DEPLOY_CONFICTS;
                }
            }

            try
            {
                d->m_hostAppDepoy->synchronizeFiles();
                KMInfo("Synchronization complete!");
            }
            catch (const std::exception &e)
            {
                KMError("Error during synchronization: " + std::string(e.what()));
            }
        }
        else if (downloadRef.ref.kind == "app")
        {
            // create current symbolic path
            fs::path completedIdPath = layersPath / downloadRef.completedRef;

            // modify service file
            fs::path serviceFileDirectoryPath = versionDataPath / "entries" / "usr" / "share" / "dbus-1" / "services";

            if (fs::exists(serviceFileDirectoryPath))
            {
                modifyServiceFile(downloadRef, serviceFileDirectoryPath.string());
            }
            else
            {
                fs::path serviceFileDirectoryPath = versionDataPath / "entries" / "share" / "dbus-1" / "services";
                modifyServiceFile(downloadRef, serviceFileDirectoryPath.string());
            }

            // Create binData file: entries/bin/ref.id
            fs::path binData;

            if (fs::exists(versionDataPath / "entries" / "usr"))
            {
                binData = versionDataPath / "entries" / "usr" / "bin";
            }
            else
            {
                binData = versionDataPath / "entries" / "bin";
            }

            kmlogger.debug("Check directory:  %s", binData.string().c_str());
            if (fs::exists(binData) || fs::create_directories(binData))
            {
                kmlogger.info("create diretory %s success", binData.string().c_str());
            }

            fs::path binDataRef = binData / downloadRef.ref.id;
            createExportBinShellScript(downloadRef, binDataRef.string());

            // deploy data: move "app/ref.id/current/active/entries/" to "/var/opt/kaiming/"
            // fs::path entriessPath = basePath / "entriess"; // For immutable system, we sheild this
            fs::path basePath = d->m_folder->getPath();
            fs::path exportsPath = d->m_folder->getExportsPath();
            fs::path appEntriesPath = versionDataPath / "entries";
            fs::path exportsSharePath = d->m_folder->getExportsSharePath();
            fs::path exportsBinPath = d->m_folder->getExportsBinPath();

            // 创建目标目录
            if (!fs::exists(exportsPath))
            {
                fs::create_directory(exportsPath);
            }

            if (!fs::exists(exportsSharePath))
            {
                fs::create_directory(exportsSharePath);
            }

            if (!fs::exists(exportsBinPath))
            {
                fs::create_directory(exportsBinPath);
            }

            // 递归遍历源目录export/并处理文件
            modifyExportsDirectory(downloadRef, appEntriesPath.string(), exportsPath.string());
            modifyExportsDirectory(downloadRef, appEntriesPath.string(), basePath.string());
            kmlogger.debug("Exports files symlinked to /opt/kaiming/exports directory successfully.");

            // 生成应用desktop, icon, service等缓存
            std::vector<std::string> triggerCachePaths = {"/opt/kaiming-tools/share/kaiming/shells/gtk-icon-cache.trigger", "/opt/kaiming-tools/share/kaiming/shells/mime-database.trigger", "/opt/kaiming-tools/share/kaiming/shells/desktop-database.trigger"};

            runMultiperTriggerUpdateCacheCommand(triggerCachePaths);
        }

        // 修改文件夹属主为当前用户，处理 run 运行的权限问题
        modifyDirOwnership(idPath);

        // Todo: Pruning repo: ostree_repo_prune()

        // KMFileUtils::createFileIfNotExist(deployDataFile.string());

        // 生成所有文件列表文件
        std::cout << "\nWaiting for generate " << downloadRef.name << "'s deploy file ..." << "\n";
        bool isFound;
        
        if (downloadRef.ref.kind == "app")
        {
            isFound = getAllAppFilesInDirectory(versionDataPath.string(), d->m_installedFiles);
        }
        else
        {
            isFound = getAllBaseFilesInDirectory(versionDataPath.string(), d->m_installedFiles);
        }

        if (!isFound)
        {
            std::cout << "Get installed file failed!" << std::endl;
        }

        fs::path deployDataFile = versionDataPath / "deploy";
        bool isDeploy = createInstalledFile(deployDataFile.string());
        if (!isDeploy)
        {
            std::cout << "Generate installed deploy file failed!" << std::endl;
        }

        fs::path infoListFile = d->m_folder->getInfoPath() / (downloadRef.ref.id + ".list");
        writeInstalledFilesToList(infoListFile.string());

        if (downloadRef.ref.module == "devel")
        {
            modifyDirOwnership(KMStorageDir::getUserDevelDataDirLocation());
        }

        // 创建 deploy ref
        ostreeManager.updateDeployRef(downloadRef.completedRef, latestCommit);
    }
    d->m_pmDownloadRefs.clear();
    d->m_pmFuzzyMatchRefs.clear();
    d->m_pmRefDownloadList.clear();
    kmlogger.info("部署成功");

    return KM_ERROR_NO;
}

void KMPackageManager::changeOwnership(const fs::path &path, uid_t uid, gid_t gid)
{
    chown(path.c_str(), uid, gid);
}

void KMPackageManager::modifyDirectoryOwnership(const std::string &directory)
{
    const char *home = std::getenv("SUDO_USER");
    struct passwd *pw = getpwnam(home);
    if (pw == nullptr)
    {
        return;
    }
    uid_t uid = pw->pw_uid;
    gid_t gid = pw->pw_uid;
    try
    {
        for (const auto &entry : fs::recursive_directory_iterator(directory))
        {
            changeOwnership(entry.path(), uid, gid);
        }
        changeOwnership(directory, uid, gid);
    }
    catch (const fs::filesystem_error &e)
    {
        std::cerr << "Error accessing " << directory << ": " << e.what() << std::endl;
    }
}

void KMPackageManager::modifyDirOwnership(const fs::path &path)
{
    std::string loginUser = KMStorageDir::getLoginUser();
    kmlogger.info("Current login user: %s", loginUser.c_str());

    if (loginUser.empty())
    {
        return;
    }

    string ownerShip = loginUser + ":" + loginUser;

    // 更改用户属组为当前登录用户
    std::vector<std::string> args;
    args.push_back("-R");
    args.push_back(ownerShip);
    args.push_back(path.string());

    if (!KMProcessUtils::spawn("chown", args))
    {
        kmlogger.error("Failed to chown file:  %s ", path.string().c_str());
    }
}

int KMPackageManager::deployOfflinePackage(std::map<std::string, string> &mountMap)
{
    fs::path basePath = d->m_folder->getPath();
    fs::path layersPath = basePath / "layers";

    uint64_t totalSize = 0;
    uint64_t preSize = 0;

    //计算总的包大小
    for (auto &downloadRef : d->m_pmRefOfflineList)
    {
        totalSize += downloadRef.installedSize;
    }

    kmlogger.info("部署开始");
    for (auto &downloadRef : d->m_pmRefOfflineList)
    {
        std::cout << "正在部署离线包: " << downloadRef.ref.id << " ..." << std::endl;
        kmlogger.info("正在部署 completedRef: %s", downloadRef.completedRef.c_str());
        if (downloadRef.ref.module == "devel")
        {
            layersPath = fs::path(KMStorageDir::getUserBaseDirLocation());
        }
        fs::path idPath = layersPath / downloadRef.ref.channel / downloadRef.ref.arch / downloadRef.ref.kind / downloadRef.ref.id;

        fs::path versionDataPath = layersPath / downloadRef.completedRef;
        kmlogger.debug("versionDataPath:  %s", versionDataPath.c_str());
        d->m_installedFiles.clear();
        // d->m_installedFiles.insert(idPath.string());
        d->m_installedFiles.insert(versionDataPath.string());

        if (std::filesystem::exists(versionDataPath) || std::filesystem::create_directories(versionDataPath))
        {
            kmlogger.debug("Directory created or already exists successfully!");
        }

        kmlogger.debug("Begin to copy data from mountpoint ...");
        fs::path mountValue = mountMap[downloadRef.ref.id];
        fs::path mountpointModulePath = mountValue / "layers" / downloadRef.ref.id / downloadRef.ref.module;
        if (std::filesystem::exists(mountpointModulePath))
        {
            std::string script = "rsync -a --progress";
            std::string arg1 = mountpointModulePath; // 替换为你要传递的第一个参数的值
            std::string arg2 = versionDataPath;      // 替换为你要传递的第二个参数的值
            std::string command = script + " " + arg1 + "/ " + arg2 + "/ ";

            FILE *pipe = popen(command.c_str(), "r");

            if (!pipe)
            {
                std::cerr << "Failed to run rsync command!" << std::endl;
                return 1;
            }

            int printNumber = -1;
            sharedValue = 0;
            // // 启动线程来监控rsync的进度
            std::thread progressThread(KMPackageManager::monitorProgress, pipe);

            while (printNumber != 100)
            {
                if (downloadRef.installedSize > 0)
                {
                    int currentValue = sharedValue.load(std::memory_order_relaxed);
                    if (currentValue > printNumber)
                    {
                        printNumber = currentValue;
                        //当前百分比等于已安装的+正在安装*当前包所占百分比
                        // std::string printValue =std::to_string(preSize + (currentValue * downloadRef.installedSize / totalSize));
                        std::cout << "\r" << currentValue << "%" << std::flush;
                        // progressJson = printValue + "%";
                        updateProgress();
                    }
                }

                if (feof(pipe))
                {
                    std::cout << "\r" << "100%" << std::flush;
                    break;
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 适当间隔去获取值，避免过于频繁占用资源
            }

            // 等待进度监控线程和进度条线程完成
            progressThread.join();

            // 关闭管道
            fclose(pipe);

            kmlogger.debug("Data copied from mountpoint successfully.");
        }
        else
        {
            kmlogger.error("mountpointModulePath not exists:  %s", mountpointModulePath.string().c_str());
        }

        kmlogger.debug("End to copy data from mountpoint.");

        // add "active/files/.ref" => content ""
        fs::path emptyFileRef = versionDataPath / "files/.ref";
        createFileForEmptyString(emptyFileRef.string());
        kmlogger.info("baseType:  %s", downloadRef.ref.kind.c_str());

        d->m_hostAppDepoy->setHostAppConfig(versionDataPath, downloadRef.ref.id);
        if (d->m_hostAppDepoy->loadHostAppInfo())
        {
            d->m_hostAppDepoy->collectSynchronizedFiles();
            if (currentRefIsUninstalled(downloadRef))
            {
                KMInfo("ok already installed!");
            }
            else
            {
                KMInfo("ok not installed!");
                if (d->m_hostAppDepoy->checkFileConflicts())
                {
                    std::cout << "已安装,请先卸载冲突的软件包" << std::endl;
                    KMError("uninstall conflicting software packages first!");
                    d->m_okFile->umountOK();
                    return KM_ERROR_DEPLOY_CONFICTS;
                }
            }

            try
            {
                d->m_hostAppDepoy->synchronizeFiles();
                KMInfo("Synchronization complete!");
            }
            catch (const std::exception &e)
            {
                KMError("Error during synchronization: " + std::string(e.what()));
            }
        }
        else if (downloadRef.ref.kind == "app")
        {
            // create current symbolic path
            fs::path completedIdPath = layersPath / downloadRef.completedRef;

            // modify service file
            fs::path serviceFileDirectoryPath = versionDataPath / "entries" / "usr" / "share" / "dbus-1" / "services";

            if (fs::exists(serviceFileDirectoryPath))
            {
                modifyServiceFile(downloadRef, serviceFileDirectoryPath.string());
            }
            else
            {
                fs::path serviceFileDirectoryPath = versionDataPath / "entries" / "share" / "dbus-1" / "services";
                modifyServiceFile(downloadRef, serviceFileDirectoryPath.string());
            }

            // Create binData file: entries/bin/ref.id
            fs::path binData;

            if (fs::exists(versionDataPath / "entries" / "usr"))
            {
                binData = versionDataPath / "entries" / "usr" / "bin";
            }
            else
            {
                binData = versionDataPath / "entries" / "bin";
            }
            kmlogger.debug("Check directory:  %s", binData.string().c_str());
            if (fs::exists(binData) || fs::create_directories(binData))
            {
                kmlogger.info("create diretory %s success", binData.string().c_str());
            }

            fs::path binDataRef = binData / downloadRef.ref.id;
            createExportBinShellScript(downloadRef, binDataRef.string());

            // deploy data: move "app/ref.id/current/active/entries/" to "/var/opt/kaiming/"
            // fs::path entriessPath = basePath / "entriess"; // For immutable system, we sheild this
            fs::path exportsPath = d->m_folder->getExportsPath();
            fs::path appEntriesPath = versionDataPath / "entries";
            fs::path exportsSharePath = d->m_folder->getExportsSharePath();
            fs::path exportsBinPath = d->m_folder->getExportsBinPath();

            // 创建目标目录
            if (!fs::exists(exportsPath))
            {
                fs::create_directory(exportsPath);
            }

            if (!fs::exists(exportsSharePath))
            {
                fs::create_directory(exportsSharePath);
            }

            if (!fs::exists(exportsBinPath))
            {
                fs::create_directory(exportsBinPath);
            }

            // 递归遍历源目录export/并处理文件
            modifyExportsDirectory(downloadRef, appEntriesPath.string(), exportsPath.string());
            modifyExportsDirectory(downloadRef, appEntriesPath.string(), basePath.string());
            kmlogger.debug("Exports files symlinked to /opt/kaiming/exports directory successfully.");

            // 生成应用desktop, icon, service等缓存
            std::vector<std::string> triggerCachePaths = {"/opt/kaiming-tools/share/kaiming/shells/gtk-icon-cache.trigger", "/opt/kaiming-tools/share/kaiming/shells/mime-database.trigger", "/opt/kaiming-tools/share/kaiming/shells/desktop-database.trigger"};

            runMultiperTriggerUpdateCacheCommand(triggerCachePaths);

            // KMFileUtils::createFileIfNotExist(deployDataFile.string());
        }

        // 修改文件夹属主为当前用户，处理 run 运行的权限问题
        modifyDirOwnership(idPath);

        // 生成所有文件列表文件
        std::cout << "\nWaiting for generate " << downloadRef.name << "'s deploy file ..." << "\n";
        bool isFound;

        if (downloadRef.ref.kind == "app")
        {
            isFound = getAllAppFilesInDirectory(versionDataPath.string(), d->m_installedFiles);
        }
        else
        {
            isFound = getAllBaseFilesInDirectory(versionDataPath.string(), d->m_installedFiles);
        }
         
        if (!isFound)
        {
            std::cout << "Get installed file failed!" << std::endl;
        }

        fs::path deployDataFile = versionDataPath / "deploy";
        bool isDeploy = createInstalledFile(deployDataFile.string());
        if (!isDeploy)
        {
            std::cout << "Generate installed deploy file failed!" << std::endl;
        }

        fs::path infoListFile = d->m_folder->getInfoPath() / (downloadRef.ref.id + ".list");
        writeInstalledFilesToList(infoListFile.string());

        if (downloadRef.ref.module == "devel")
        {
            modifyDirOwnership(KMStorageDir::getUserDevelDataDirLocation());
        }
        // Todo: Pruning repo: ostree_repo_prune()
        std::cout << "成功部署离线包: " << downloadRef.ref.id << " " << std::endl;
    }

    // std::cout << "100%" << std::endl;
    progressJson = "100%";
    updateProgress();
    d->m_okFile->umountOK();
    kmlogger.info("部署成功");

    return KM_ERROR_NO;
}

void KMPackageManager::createFileForEmptyString(const std::string &filename)
{
    // 打开文件进行检查
    std::ifstream inputFile(filename);
    if (inputFile.is_open())
    {
        kmlogger.error("File already exists:  %s", filename.c_str());
        inputFile.close();
        return;
    }

    // 创建文件并打开输出流
    std::ofstream outputFile(filename);
    if (!outputFile.is_open())
    {
        kmlogger.error("Failed to create file:  %s", filename.c_str());
        return;
    }

    // 写入空字符串到文件
    outputFile << "";

    // 关闭文件
    outputFile.close();
}

void KMPackageManager::modifyServiceFile(KMPMRef &pmRef, string serviceFileDirectoryPath)
{
    std::vector<std::string> files;
    files.clear();

    bool noModifyServiceFileFlag = false;

    // 调用函数获取目录下所有文件
    bool success = getAllFilesInDirectory(serviceFileDirectoryPath, files);
    if (success)
    {
        for (const auto &file : files)
        {
            if (file.find(".service") != std::string::npos)
            {
                string serviceFileName = file;
                kmlogger.debug("serviceFileName:  %s", serviceFileName.c_str());

                std::vector<std::string> serviceDatas = getDataFromKVFile(serviceFileName);

                for (auto &line : serviceDatas)
                {
                    // 修改 Exec 字段
                    size_t eqPos = line.find("Exec=");
                    if (eqPos != std::string::npos && eqPos == 0)
                    {
                        std::string value = line.substr(eqPos + strlen("Exec="));
                        if (value.find(" run") != std::string::npos)
                        {
                            // 第一次已进行修改，因此不修改当前文件
                            noModifyServiceFileFlag = true;
                        }

                        string serviceExec = "Exec=";
                        string content = serviceExec.append("/usr/bin/kaiming run ").append("--branch=").append(pmRef.ref.channel).append(" ").append("--arch=").append(pmRef.ref.arch).append(" ").append("--command=").append(value).append(" ").append(pmRef.ref.id);
                        line = content;
                    }
                }

                if (!noModifyServiceFileFlag)
                {
                    // 将修改后的内容写回 .service 文件
                    if (setDataToKVFile(serviceFileName, serviceDatas))
                    {
                        kmlogger.debug("Desktop file modified successfully.");
                    }
                }
            }
        }
    }
    else
    {
        kmlogger.error("Failed to get files in directory.");
    }
}

bool KMPackageManager::getAllFilesInDirectory(const std::string &directoryPath, std::vector<std::string> &files)
{
    try
    {
        // 遍历目录中的文件
        for (const auto &entry : fs::recursive_directory_iterator(directoryPath, fs::directory_options::skip_permission_denied | fs::directory_options::follow_directory_symlink))
        {
            if (fs::is_symlink(entry.path()) && fs::read_symlink(entry.path()) == entry.path())
            {
                continue;
            }

            // 将文件路径添加到文件列表中
            files.push_back(entry.path().string());
        }

        return true; // 成功获取文件列表
    }
    catch (const std::exception &e)
    {
        kmlogger.error("Failed to get files: %s", e.what());
        return false; // 获取文件列表失败
    }
}

bool KMPackageManager::getAllBaseFilesInDirectory(const std::string &directoryPath, std::set<std::string> &files)
{
    try
    {
        // 遍历目录中的文件
        for (const auto &entry : fs::recursive_directory_iterator(directoryPath, fs::directory_options::skip_permission_denied ))
        {
            if (fs::is_symlink(entry.path()) && fs::read_symlink(entry.path()) == entry.path())
            {
                continue;
            }

            // 将文件路径添加到文件列表中
            files.insert(entry.path().string());
        }

        return true; // 成功获取文件列表
    }
    catch (const std::exception &e)
    {
        kmlogger.error("Failed to get files: %s", e.what());
        return false; // 获取文件列表失败
    }
}

bool KMPackageManager::getAllAppFilesInDirectory(const std::string &directoryPath, std::set<std::string> &files)
{
    try
    {
        // 遍历目录中的文件
        for (const auto &entry : fs::recursive_directory_iterator(directoryPath, fs::directory_options::skip_permission_denied  | fs::directory_options::follow_directory_symlink))
        {
            if (fs::is_symlink(entry.path()) && fs::read_symlink(entry.path()) == entry.path())
            {
                continue;
            }

            // 将文件路径添加到文件列表中
            files.insert(entry.path().string());
        }

        return true; // 成功获取文件列表
    }
    catch (const std::exception &e)
    {
        kmlogger.error("Failed to get files: %s", e.what());
        return false; // 获取文件列表失败
    }
}

std::vector<std::string> KMPackageManager::getDataFromKVFile(const std::string &filename)
{
    std::vector<std::string> lines;
    std::ifstream file(filename);
    if (file.is_open())
    {
        std::string line;
        while (std::getline(file, line))
        {
            lines.push_back(line);
        }
        file.close();
    }
    else
    {
        kmlogger.error("Failed to open file::  %s", filename.c_str());
    }
    return lines;
}

bool KMPackageManager::setDataToKVFile(const std::string &filename, const std::vector<std::string> &newLines)
{
    std::ofstream file(filename);
    if (file.is_open())
    {
        for (const auto &line : newLines)
        {
            file << line << std::endl;
        }
        file.close();
        return true;
    }
    else
    {
        kmlogger.error("inFailed to open file for writingdex:  %s", filename.c_str());
        return false;
    }
}

void KMPackageManager::modifyDesktopFile(KMPMRef &pmRef, string exportDesktopFilePath)
{
    kmlogger.info("Begin to exportDesktopFilePath: %s\n", exportDesktopFilePath.c_str());
    std::vector<std::string> desktopDatas = getDataFromKVFile(exportDesktopFilePath);

    bool needAddKaimingTag = false;

    // 遍历 desktopDatas 通过每行 line 修改需要的字段
    for (auto &line : desktopDatas)
    {
        // 跳过开头为 # 的注释字段
        if (line[0] == '#')
        {
            continue;
        }

        // 注释以下内容处理无图标或开始菜单无法点击运行问题
        std::vector<std::string> annotationVector = {
            "DBusActivatable", // 注释 DBusActivatable 字段，否则org.gnome.Sudoku包任务栏无图标
            "StartupNotify",   // 注释 StartupNotify 字段，否则org.gnome.Aisleriot包任务栏无图标
            "TryExec"          // 注释 TryExec 字段，否则org.gnome.Gitg和org.ggsoft.etw在开始菜单无法点击运行
        };

        bool needAnnotation = false;
        for (auto it = annotationVector.begin(); it != annotationVector.end(); ++it)
        {
            if (line.find(*it) == 0)
            {
                needAnnotation = true;
                break;
            }
        }

        if (needAnnotation)
        {
            line = "# " + line;
            continue;
        }

        // 修改 Exec 字段，否则开始菜单应用运行不起来
        size_t eqPos = line.find("Exec=");
        if (eqPos != std::string::npos && eqPos == 0)
        {
            std::string value = line.substr(eqPos + strlen("Exec="));
            if (value.find(" run") != std::string::npos)
            {
                // 第一次已进行修改，或者代表已经有可用 /usr/bin/kaiming run，因此不修改。案例有在线源中的 org.gnome.baobab 包。
                continue;
            }

            // formatExec correct: --command=baobab org.gnome.baobab %U
            string formatExec = d->m_util->formatExecString(value, pmRef.ref.id);
            kmlogger.info("formatExec: %s", formatExec.c_str());

            // kigo %u -qwindowicon kigo -qwindowtitle %c => kigo --file-forwarding org.kde.kigo @@u
            // %u @@ -qwindowicon kigo -qwindowtitle %c
            string serviceExec = "Exec=";
            string content = serviceExec.append("/usr/bin/kaiming run ").append(formatExec);
            line = content;
        }

        // 保留，暂不修改 Icon 字段
        if (line.find("Icon=") != std::string::npos)
        {
            // Todo: Modify Icon
        }

        // 新增 X-Kaiming 字段，用于SDK，开始菜单等获取软件包名
        if (line.find("X-Kaiming=") != std::string::npos)
        {
            needAddKaimingTag = false;
        }
        else
        {
            needAddKaimingTag = true;
        }
    }

    if (needAddKaimingTag)
    {
        for (auto it = desktopDatas.begin(); it != desktopDatas.end(); ++it)
        {
            if (it->find("[Desktop Entry]") != std::string::npos)
            {
                string kaimingTag = "X-Kaiming=" + pmRef.ref.id;
                desktopDatas.insert(it + 1, kaimingTag);
                break;
            }
        }
    }

    // 将修改后的内容写回 .desktop 文件
    if (!setDataToKVFile(exportDesktopFilePath, desktopDatas))
    {
        kmlogger.error("Desktop file modified failed.");
    }
    return;
}

bool KMPackageManager::createExportBinShellScript(KMPMRef pmRef, string fileName)
{
    // 设置内容
    string shellHead = "#!/bin/sh";
    string content = shellHead.append("\nexec ").append("/usr/bin/kaiming run --branch=").append(pmRef.ref.channel).append(" --arch=").append(pmRef.ref.arch).append(" ").append(pmRef.ref.id).append(" \"$@\"\n");

    kmlogger.info("export bin bash content:\n%s", content.c_str());
    // 创建文件并写入内容
    std::ofstream file(fileName);
    if (file.is_open())
    {
        file << content;
        file.close();
    }
    else
    {
        kmlogger.error("Failed to open file:  %s", fileName.c_str());
        return false;
    }

    // 设置文件权限为 0755
    if (chmod(fileName.c_str(), 0755) != 0)
    {
        kmlogger.error("Failed to set file permission for:  %s", fileName.c_str());
        return false;
    }

    return true;
}

bool KMPackageManager::createInstalledFile(string fileName)
{
    // 设置内容
    string content;

    for (auto &installedFile : d->m_installedFiles)
    {
        content = content.append(installedFile).append("\n");
    }

    // fix: runtime, base多版本安装时，已有版本deploy 会修改当前安装版本
    if (fs::exists(fileName))
    {
        fs::remove(fileName);
    }

    // 创建文件并写入内容
    std::ofstream file(fileName);
    if (file.is_open())
    {
        file << content;
        file.close();
    }
    else
    {
        kmlogger.error("Failed to open file:  %s", fileName.c_str());
        return false;
    }

    // 设置文件权限为 0755
    if (chmod(fileName.c_str(), 0755) != 0)
    {
        kmlogger.error("Failed to set file permission for:  %s", fileName.c_str());
        return false;
    }

    return true;
}

void KMPackageManager::writeInstalledFilesToList(const std::string &filePath)
{
    fs::path dirPath = fs::path(filePath).parent_path();

    if (!fs::exists(dirPath))
    {
        if (!fs::create_directories(dirPath))
        {
            KMError("Error creating directory: " + dirPath.string());
            return;
        }
    }

    std::ofstream outFile(filePath);

    if (!outFile)
    {
        KMError("Error opening file: " + filePath);
        return;
    }

    for (const auto &installedFile : d->m_installedFiles)
    {
        outFile << installedFile << "\n";
    }

    outFile.close();
}

bool KMPackageManager::createFileIfNotExist(string fileName)
{
    return false;
}

void KMPackageManager::modifyExportsDirectory(KMPMRef &pmRef, const std::string &srcDir, const std::string &destDir)
{
    for (const auto &entry : fs::directory_iterator(srcDir))
    {
        if (fs::is_directory(entry))
        {
            // 递归处理子目录
            std::string subSrcDir = entry.path().string();
            std::string subDestDir = destDir + "/" + entry.path().filename().string();

            string removeStr = "/usr";
            size_t pos = subDestDir.find(removeStr);
            if (pos != std::string::npos)
            {
                subDestDir.erase(pos, removeStr.length());
            }

            fs::create_directory(subDestDir);
            modifyExportsDirectory(pmRef, subSrcDir, subDestDir);
        }
        else
        {
            // 处理文件
            std::string srcFilePath = entry.path().string();
            std::string destFilePath = destDir + "/" + entry.path().filename().string();
            kmlogger.debug("srcFilePath:%s destFilePath:%s", srcFilePath.c_str(), destFilePath.c_str());

            string removeStr = "/usr";
            size_t pos = destFilePath.find(removeStr);
            if (pos != std::string::npos)
            {
                destFilePath.erase(pos, removeStr.length());
            }
            kmlogger.debug("srcFilePath:%s destFilePath:%s", srcFilePath.c_str(), destFilePath.c_str());

            if (fs::exists(fs::path(destFilePath)) && fs::is_symlink(fs::path(destFilePath)))
            {
                kmlogger.info("destFilePath  %s exists.", destFilePath.c_str());
                d->m_installedFiles.insert(destFilePath);
                continue;
            }

            if (srcFilePath.find(".desktop") != std::string::npos || srcFilePath.find(".service") != std::string::npos || srcFilePath.find(".svg") != std::string::npos || srcFilePath.find(".png") != std::string::npos)
            {

                // 如果是 .desktop, .service, .svg 文件，则创建相对路径软链接到目标目录
                // 此处以 ".desktop" 为后缀，否则会出现 "org.freedesktop.impl.portal.desktop.gtk.service" 也会进行修改。
                if (KMStringUtils::endsWith(srcFilePath, ".desktop"))
                {
                    modifyDesktopFile(pmRef, srcFilePath);
                }

                // 获取 srcFilePath 相对于 destFilePath 的相对路径
                std::string relativePath = fs::relative(fs::path(srcFilePath), fs::path(destFilePath).parent_path()).string();
                kmlogger.info("Export .desktop, .service, .svg, .png relativePath:  %s destFilePath: %s", relativePath.c_str(), destFilePath.c_str());

                if (fs::is_symlink(fs::path(destFilePath)))
                {
                    // 如果存在，删除该文件或链接
                    kmlogger.info("destFilePath  %s exists. delete it.", destFilePath.c_str());
                    fs::remove(fs::path(destFilePath));
                }

                fs::create_symlink(fs::path(relativePath), fs::path(destFilePath));
                d->m_installedFiles.insert(destFilePath);
            }
            else if (srcFilePath.find("entries/usr/bin") != std::string::npos || srcFilePath.find("entries/bin") != std::string::npos)
            {
                // 如果是 entries/bin 二进制文件，则创建相对路径软链接到目标目录
                std::string relativePath = fs::relative(fs::path(srcFilePath), fs::path(destFilePath).parent_path()).string();
                kmlogger.info("Export bin relativePath:  %s destFilePath: %s", relativePath.c_str(), destFilePath.c_str());

                // 使用 fs::exists 检测软链接的存在，它会返回目标文件的存在状态，而不是软链接本身。因此，使用 fs::is_symlink 是判断软链接是否存在的正确方法。
                if (fs::is_symlink(fs::path(destFilePath)))
                {
                    // 如果存在，删除该文件或链接
                    kmlogger.info("destFilePath  %s exists. delete it.", destFilePath.c_str());
                    fs::remove(fs::path(destFilePath));
                }

                fs::create_symlink(fs::path(relativePath), fs::path(destFilePath));
                d->m_installedFiles.insert(destFilePath);
            }
        }
    }
}

void KMPackageManager::runMultiperTriggerUpdateCacheCommand(const vector<string> &cacheShellPaths)
{
    for (const auto &path : cacheShellPaths)
    {
        runTriggerUpdateCacheCommand(path);
    }
}

void KMPackageManager::runTriggerUpdateCacheCommand(const std::string &cacheShellPath)
{
    // 构建命令字符串，将脚本路径和参数拼接在一起
    std::string command = cacheShellPath + " " + "/opt/kaiming";

    kmlogger.info("Generate cache command: %s", command.c_str());

    // 执行命令
    int result = std::system(command.c_str());
    if (result != 0)
    {
        kmlogger.error("Failed to execute command:  %s", command.c_str());
    }
}

vector<string> KMPackageManager::getGLDrivers()
{
    static std::once_flag initFlag;
    static std::vector<std::string> drivers;

    std::call_once(initFlag, [=]()
                   {
                       const char *env = std::getenv("KAIMING_GL_DRIVERS");
                       if (env != nullptr && *env != '\0')
                       {
                           drivers = parseGLDriversFromEnv();
                       }
                       else
                       {
                           drivers = parseGLDriversFromSystem();
                       }
                   });

    return drivers;
}

vector<string> KMPackageManager::parseGLDriversFromEnv()
{
    std::vector<std::string> result;
    const char *env = std::getenv("KAIMING_GL_DRIVERS");
    std::string envStr(env);
    std::stringstream ss(envStr);
    std::string item;

    while (std::getline(ss, item, ':'))
    {
        result.push_back(item);
    }

    return result;
}

vector<string> KMPackageManager::parseGLDriversFromSystem()
{
    std::vector<std::string> result;
    std::ifstream nvidiaVersionFile("/sys/module/nvidia/version");
    std::string nvidiaVersion;

    if (nvidiaVersionFile && std::getline(nvidiaVersionFile, nvidiaVersion))
    {
        // Remove leading/trailing whitespace
        nvidiaVersion.erase(nvidiaVersion.begin(), std::find_if(nvidiaVersion.begin(), nvidiaVersion.end(), [](int ch)
                                                                { return !std::isspace(ch); }));
        nvidiaVersion.erase(std::find_if(nvidiaVersion.rbegin(), nvidiaVersion.rend(),
                                         [](int ch)
                                         {
                                             return !std::isspace(ch);
                                         })
                                .base(),
                            nvidiaVersion.end());

        // Replace dots with dashes
        std::replace(nvidiaVersion.begin(), nvidiaVersion.end(), '.', '-');
        result.push_back("nvidia-" + nvidiaVersion);
    }

    result.push_back("default");
    result.push_back("host");

    return result;
}

// 线程函数：实时读取rsync的输出并解析进度信息
void KMPackageManager::monitorProgress(FILE *pipe)
{
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), pipe) != nullptr)
    {
        std::string line(buffer);
        // 查找包含百分比的行，表示文件传输的进度
        size_t firstPos = line.find('=');
        if (firstPos != std::string::npos)
        {
            size_t secondPos = line.find(')', firstPos + 1);
            // 提取进度百分比
            std::string progresStr = line.substr(firstPos, secondPos); // 获取进度
            size_t thirdPos = progresStr.find('/');
            std::string numBeforeStr = progresStr.substr(1, thirdPos - 1);
            int numBefore, numAfter;
            std::stringstream(numBeforeStr) >> numBefore;
            std::string numAfterStr = progresStr.substr(thirdPos + 1, progresStr.length() - thirdPos - 3);
            std::stringstream(numAfterStr) >> numAfter;
            int result = (numAfter - numBefore);
            int divid = (int)((double)result / numAfter * 100);
            sharedValue.store(divid, std::memory_order_relaxed); // 在线程中修改共享变量的值
        }
    }
}

int KMPackageManager::verifySignature(KMOSTreeHandler &ostreeManager, PackageManagerOptions pmOptions)
{
    fs::path tmpPath = fs::path("/tmp");

    kmlogger.info("Begin to deploy temporary files to /tmp.");
    for (auto &downloadRef : d->m_pmRefDownloadList)
    {
        d->m_installedFiles.clear();
        kmlogger.info("completedRef: %s", downloadRef.completedRef.c_str());
        int verifyResult = KM_ERROR_NO;

        // 判断是否是 base 或 runtime，若是，则暂时不需要验签，直接安装
        if (downloadRef.ref.kind == "base" || downloadRef.ref.kind == "runtime")
        {
            return KM_ERROR_NO;
        }

        fs::path idPath = tmpPath / downloadRef.ref.id;
        kmlogger.debug("idPath:  %s", idPath.c_str());
        d->m_installedFiles.insert(idPath.string());

        if (std::filesystem::exists(idPath) || std::filesystem::create_directories(idPath))
        {
            kmlogger.debug("Directory created or already exists successfully!");
        }

        kmlogger.debug("Begin to checkout ...");
        string latestCommit = ostreeManager.readLatestCommit(downloadRef.completedRef);
        // 生成files.md5等文件,从 OSTree 仓库中检出（checkout）指定的提交（commit），并将内容部署到指定的路径
        ostreeManager.checkout(latestCommit, idPath.string());
        kmlogger.debug("End to checkout.");
        kmlogger.info("End to deploy files.");

        // 判断是否存在签名工具
        bool isSignTool = isKylinFileSignToolPresent();
        if (isSignTool)
        {
            kmlogger.info("kylin-signtool exists.");
            std::string sigFilesPath = (idPath / "sig").string();
            std::string filesMd5 = KMStringUtils::buildFilename(idPath, "files.md5");
            std::string filesSign = KMStringUtils::buildFilename(sigFilesPath, "files.sig");
            std::string filesPem = KMStringUtils::buildFilename(sigFilesPath, "files.pem");

            // 签名工具存在，则判断签名文件.md5是否存在
            if (KMFileUtils::fileExists(filesMd5))
            {
                kmlogger.info("files.md5 exists.");
                kmlogger.info("开始验签");
                std::string command = "kylinfilesigntool -v \"" + filesMd5 + "\" -s \"" + filesSign + "\" -c \"" + filesPem + "\"";
                verifyResult = std::system(command.c_str());
                if (verifyResult != KM_ERROR_NO)
                {
                    kmlogger.info("验签失败，停止安装");
                    std::cout << _("Signature verification failed, installation stopped") << std::endl;
                    verifyResult = KM_ERROR_SIGN_FAILED;
                }
                else
                {
                    kmlogger.info("验签成功");
                }
            }
            else
            {
                kmlogger.info("签名文件不存在，停止安装");
                std::cout << _("Signature verification failed, installation stopped") << std::endl;
                verifyResult = KM_ERROR_NO_MD5_FILES;
            }
        }
        else
        {
            kmlogger.info("签名工具不存在，不进行验签");
        }

        if (!removeTmpDeployFiles(downloadRef.ref.id))
        {
            kmlogger.info("删除临时目录失败");
            return KM_ERROR_DELETE_DIRECTORY_FAILED;
        }

        if (verifyResult != KM_ERROR_NO)
        {
            d->m_pmDownloadRefs.clear();
            d->m_pmFuzzyMatchRefs.clear();
            d->m_pmRefDownloadList.clear();
            return verifyResult;
        }
    }
    return KM_ERROR_NO;
}

// 判断签名工具是否存在
bool KMPackageManager::isKylinFileSignToolPresent()
{
    int result = std::system("which kylinfilesigntool > /dev/null 2>&1");
    // 结果为0，找到工具
    return (result == 0);
}