#include "KMPackageManager.h"

#include "common/KMLogger.h"
#include "common/KMInstalledAppQuery.h"
#include "common/KMJsonHelper.h"
#include "common/semver.hpp"

#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::once_flag KMPackageManager::initFlag;
std::vector<std::string> KMPackageManager::drivers;

class KMPackageManager::Private
{
public:
    std::shared_ptr<KMFolder> m_folder;
    std::shared_ptr<KMRemoteSummary> m_remoteSummary;
    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; // 仓库路径


    KMPMRef m_pmRef;                  // 单独ref,用于存储到 d->m_refUserList中
    vector<KMPMRef> m_pmRefDownloadList; // 实际上需要安装的软件列表
    vector<KMPMRef> m_pmRefSearchList; // 查询的软件列表
    vector<string> m_pmFuzzyMatchRefs; // 从依赖文件中模糊匹配到的 ref 列表

    stack<string> m_pmRelatedRefs; // 先遍历运行时，再遍历app。因此先压入app,之后提取的时候顺序不会乱
    vector<string> m_pmDownloadRefs; // 先遍历运行时，再遍历app。因此先压入app,之后提取的时候顺序不会乱

    map<string, KMRef> m_mapRefs;//ref映射表
    shared_ptr<KMOSTreeHandler> m_ostreeHandler;

};

KMPackageManager::KMPackageManager()
    : d(make_shared<Private>())
{
    d->m_folder = shared_ptr<KMFolder>(new KMFolder(KAIMING_SYSTEM_PATH, false));
    d->m_remoteSummary = shared_ptr<KMRemoteSummary>(new KMRemoteSummary());
    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);
}

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);

    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;

    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;
    }

    // 获取真正安装列表
    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 (KMUtil::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;
    }

    // 部署包
    return deploy(ostreeManager);
}

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;

    vecInstall.push_back(name);

    ret = install(vecInstall, pmOption);

    error = ret;

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

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

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

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

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);

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

        if(!d->m_folder->isInstalled(name,pmRef))
        {
            kmlogger.pinfo("%s not installed!", name.c_str());
            continue;
            
        }
        kmlogger.pinfo("find installed package %s", name.c_str());


        perUninstallList.push_back(name);

        if(pmOptions.unusedYes){

            // 加载所有的info.json文件信息
            infoMap = loadAllInfoJsonFiles();
            // 查找并处理该应用的依赖项
            findDependencies(name,perUninstallList);

        } //默认不删除runtime和base

        printUninstallList(perUninstallList);

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

        for (auto it = perUninstallList.begin(); it != perUninstallList.end(); /* empty */)
        {
            const auto& id = *it; // 获取当前的 id
            if (d->m_folder->isApp(id))
            {
                if (!uninstallApp(id))
                {
                    return KM_ERROR_DELETE_DIRECTORY_FAILED;
                }

                if (pmOptions.deletedataYes)
                {
                    deleteUserData(id);
                }

                it = perUninstallList.erase(it); // 删除当前元素，返回指向下一个元素的迭代器
            }
            else if (d->m_folder->isRuntime(id))
            {
                if (!uninstallRuntime(id))
                {
                    return KM_ERROR_DELETE_DIRECTORY_FAILED;
                }
                it = perUninstallList.erase(it); // 删除当前元素
            }
            else
            {
                if (!uninstallBase(id))
                {
                    return KM_ERROR_DELETE_DIRECTORY_FAILED;
                }
                it = perUninstallList.erase(it); // 删除当前元素
            }

            // 从本地 repo 中删除引用
            if (!deleteRefsFromRepo(id))
            {
                return KM_ERROR_DELETE_REF_TAG_FAILED;
            }
        }   
        if(perUninstallList.empty()) // 检查是否为空
        {
            kmlogger.pinfo("\033[1;32muninstall packages ok.\033[0m");
        }  
      
    }
    return KM_ERROR_NO;
}

void KMPackageManager::findDependencies(const std::string &targetId,std::vector<std::string> &perUninstallList)
{
    // 检查目标id是否在infoMap中
    if (infoMap.find(targetId) == infoMap.end()) {
        std::cout << targetId << " not found in info.json files.\n";
        return;
    }
    
     // 获取目标应用的info.json
    KMInfoJson targetInfo = infoMap[targetId];
    infoMap.erase(targetId); // 移除目标应用，避免重复处理

    std::string extractRuntimeName, extractBaseName;

    // Step 1: 查找不被其他应用所依赖的runtime
    if (!targetInfo.runtime.empty()) {
        KMRef runtimeRef = targetInfo.runtimeRef();
        extractRuntimeName = runtimeRef.id;
        infoMap.erase(extractRuntimeName);
         // 检查 runtime 是否被其他应用依赖
        bool isRuntimeDepended = false;
        for (const auto &pair : infoMap) {
            const KMInfoJson &info = pair.second;
            if ((info.runtimeRef().id == extractRuntimeName)&&(info.id !=targetId)) {
                isRuntimeDepended = true;
                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;
                infoMap.erase(extractBaseName);
                // 检查 base 是否被应用或 runtime 依赖
                bool isBaseDepended = false;
                for (const auto &pair : infoMap) {
                    const KMInfoJson &info = pair.second;
                    if ((info.baseRef().id  == extractBaseName)&&(info.id !=targetId)) {
                        isBaseDepended = true;
                        infoMap.erase(info.id);
                        break;
                    }
                }

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

}

std::unordered_map<std::string, KMInfoJson> KMPackageManager::loadAllInfoJsonFiles()
{
    fs::path layersPath = d->m_folder->getLayersPath();
    std::unordered_map<std::string, KMInfoJson> infoMap;
    
    // 遍历目录中的所有info.json文件
    for (const auto &dirEntry : std::filesystem::recursive_directory_iterator(layersPath)) {
        
        if (dirEntry.is_regular_file() && dirEntry.path().filename() == "info.json") {
            const auto filenameStr = dirEntry.path().string();
            
            KMInfoJson infoJson;
            infoJson.loadFile(filenameStr);
            
            // 使用文件路径作为key存储每个infoJson对象
            infoMap[infoJson.id] = infoJson;
        }
    }
    
    
    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)
    {
        printf(_("Do you want to uninstall these changes? [Y/n]: "));

        char yesOption;

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

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

    return true;
}

bool KMPackageManager::uninstallApp(const std::string &name)
{
     // 删除应用文件和目录
    kmlogger.pinfo("remove app %s install dir.", name.c_str());
  
    if (!fs::remove_all(d->m_folder->getUninstallPath() / name))
    {
        kmlogger.error("uninstall %s error, can't delete the directory.", name);
        return false;
    }

    fs::path exportPath = d->m_folder->getExportsPath();
    if (std::filesystem::exists(exportPath))
    {
        for (auto const &entryDir : fs::recursive_directory_iterator(exportPath))
        {
            if (fs::is_symlink(entryDir) && (int)fs::read_symlink(entryDir).string().find(name) > 0)
            {
                kmlogger.pinfo("remove %s", entryDir.path().c_str());
                if (!fs::remove_all(entryDir))
                {
                    kmlogger.perror("uninstall %s error, can\'t delete exports file.", name.c_str());
                    return false;
                }
            }
        }
    }

    fs::path varExportPath = d->m_folder->getVarExportsPath();

    std::vector<std::string> subDirs = { "share", "bin" };
    for (const auto &subDir : subDirs)
    {
        fs::path varExportSubDir = varExportPath / subDir;

        if (std::filesystem::exists(varExportSubDir))
        {
            for (auto const &entryDir : fs::recursive_directory_iterator(varExportSubDir))
            {
                if (fs::is_symlink(entryDir) && (int)fs::read_symlink(entryDir).string().find(name) > 0)
                {
                    kmlogger.pinfo("remove %s", entryDir.path().c_str());
                    if (!fs::remove_all(entryDir))
                    {
                        kmlogger.perror("uninstall %s error, can\'t delete exports file.", name.c_str());
                        return false;
                    }
                }
            }
        }
    }

    return true;
}

bool KMPackageManager::uninstallRuntime(const std::string &name)
{
    printf("remove runtime %s install dir.\n",name.c_str());
    //kmlogger.info("remove runtime %s install dir", name.c_str());
    if (!fs::remove_all(d->m_folder->getRuntimePath() / name ))
    {
        kmlogger.error("uninstall %s error, can't delete the directory.", name);
        return false;
    }
    return true;
    
}

bool KMPackageManager::uninstallBase(const std::string &name)
{
    printf("remove runtime %s install dir.\n",name.c_str());
    //kmlogger.info("remove base %s install dir", name.c_str());
    if (!fs::remove_all(d->m_folder->getBasePath() / name ))
    {
        kmlogger.error("uninstall %s error, can't delete the directory.", name);
        return false;
    }
    return true;
}

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::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 = KMUtil::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;
    }

    // 获取真正更新列表
    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 (KMUtil::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;
    }

    // 部署包
    return deploy(ostreeManager);
}

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 = KMUtil::isFileExpired(summaryJsonPath, 3600);
    int getSummaryState = getRemoteSummary(summaryUrl, isSummaryJsonExpired);
    d->m_parseSummaryJson->loadFile(summaryUrl);
    string completePath = d->m_parseSummaryJson->printSearchJson(vectorIds,pmOptions.arch, 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 = KMUtil::isFileExpired(summaryJsonPath, 3600);
    // int getSummaryState = getRemoteSummary(summaryUrl, isSummaryJsonExpired);
    d->m_parseSummaryJson->loadFile(summaryUrl);
    string completePath =d->m_parseSummaryJson->printSearchJson(vectorIds,pmOptions.arch, pmOptions.isPrint);

    return  completePath;

}

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


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

    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 moduleStr = pmRef.ref.module.empty() ? "" : pmRef.ref.module;

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

    Semver::KMVersion installedVersion;
    Semver::KMVersion currentVersion;

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

            // 指定版本，则检查是否已安装
            for (const auto &ref : queryVector)
            {
                installedVersion = Semver::KMVersion::parse(ref.version);
                if (installedVersion == currentVersion)
                {
                    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::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 << _("Curl download summary file failed!") << 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 << _("Curl download summary file failed!") << std::endl;

                return KM_ERROR_CURL_DOWNLOAD_FAILED;
            }
        }
    }
    else
    {
        // 依赖文件清单不存在，需要下载
        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 << _("Curl download summary file failed!") << 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();

    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;
        }

        switch(taskType)
        {
        case TASK_TYPE_INSTALL:
            // 已安装当前软件包或指定版本包则不再安装
            if (currentRefIsInstalled(pmRef))
            {
                kmlogger.info("当前软件包 %s 已安装", name.c_str());
                continue;
            }
            break;
        case TASK_TYPE_UPDATE:
            // 未安装该包或该包指定版本,则不更新，直接返回
            if (!currentRefIsInstalled(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 (!currentRefIsInstalled(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 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);

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

    return KM_ERROR_NO;
}

void KMPackageManager::getDownloadRefList(TaskType taskType)
{
    for (auto &ref : d->m_pmFuzzyMatchRefs)
    {
        KMPMRef pmFuzzyRef = KMUtil::parseSummaryFuzzyKMPMRef(ref);

        switch (taskType)
        {
        case TASK_TYPE_INSTALL:
            // 安装时，过滤掉已安装的软件
            if (currentRefIsInstalled(pmFuzzyRef))
            {
                continue;
            }
            break;
        case TASK_TYPE_UPDATE:
            // 更新时也是过滤掉已安装的软件
            if (currentRefIsInstalled(pmFuzzyRef))
            {
                continue;
            }
            break;

        default:
            break;
        }

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

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

        d->m_pmRefDownloadList.push_back(pmFuzzyRef);
        globalRefDownloadListForProgress.push_back(pmFuzzyRef);
    }
}

void KMPackageManager::printDownloadRefList(const vector<KMPMRef> &downloadRefs)
{
    d->m_formatter->setColumnWidth(35, 35, 15, 10, 25, 25, 30, 25);
    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)
    {
        printf(_("Do you want to install these changes? [Y/n]: "));

        char yesOption;

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

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

    return true;
}

/**
 * @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);
        }
    }

    if (strlen(str) <= lastOutput.size())
    {
        printf("\r"); // 移动光标到行首，但不显示尾部光标
        printf("%-150s", "");
    }
    printf("\r");

    printf("%s", str);
    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)
    {
        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 = KMJsonHelper::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)
    {
        kmlogger.debug("completedRef: %s", downloadRef.completedRef.c_str());

        fs::path versionDataPath = layersPath / downloadRef.completedRef;
        kmlogger.debug("versionDataPath:  %s", versionDataPath.c_str());

        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());
        if (downloadRef.ref.kind == "app")
        {
            // create current symbolic path
            fs::path completedIdPath = layersPath / downloadRef.completedRef;

            // modify service file
            fs::path serviceFileDirectoryPath = versionDataPath / "entries" / "share" / "dbus-1" / "services";
            modifyServiceFile(downloadRef, serviceFileDirectoryPath.string());

            // modify .desktop
            string desktopFileName = downloadRef.ref.id + ".desktop";
            fs::path entriesDesktopFilePath = versionDataPath / "entries" / "share" / "applications" / desktopFileName;
            modifyDesktopFile(downloadRef, entriesDesktopFilePath.string());

            // Create binData file: entries/bin/ref.id
            fs::path 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";

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

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

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

            runMultiperTriggerUpdateCacheCommand(triggerCachePaths);
        }
        else
        {
            // Todo: handle directory "files/etc" and file "/run/host/monitor/resolv.conf"
        }

        // Todo: Pruning repo: ostree_repo_prune()

        fs::path deployDataFile = versionDataPath / "deploy";

        KMUtil::createFileIfNotExist(deployDataFile.string());

        // 创建 deploy ref
        ostreeManager.updateDeployRef(downloadRef.completedRef, latestCommit);

    }
    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;

    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)
                    {
                        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
    {
        // 清空文件列表
        files.clear();

        // 遍历目录中的文件
        for (const auto &entry : fs::directory_iterator(directoryPath))
        {
            // 将文件路径添加到文件列表中
            files.push_back(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)
{
    std::vector<std::string> desktopDatas = getDataFromKVFile(exportDesktopFilePath);

    /* Add a marker so consumers can easily find out that this launches a sandbox */
    bool needAddKaimingTag = false;
    bool noModifyDesktopFileFlag = false;

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

            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
            // line = "Icon=/path/to/new/icon";
        }

        // 新增 X-Type 字段
        if (line.find("X-Kaiming=") != std::string::npos)
        {
            needAddKaimingTag = false;
        }
        else
        {
            needAddKaimingTag = true;
        }
    }

    if (noModifyDesktopFileFlag)
    {
        return;
    }

    if (needAddKaimingTag)
    {
        string kaimingTag = "X-Kaiming=" + pmRef.ref.id;
        desktopDatas.push_back(kaimingTag);
    }

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

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::createFileIfNotExist(string fileName)
{
    return false;
}

void KMPackageManager::modifyExportsDirectory(KMPMRef &ref, 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();
            fs::create_directory(subDestDir);
            modifyExportsDirectory(ref, 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());

            if (fs::exists(fs::path(destFilePath)) && fs::is_symlink(fs::path(destFilePath)))
            {
                kmlogger.info("destFilePath  %s exists.", destFilePath.c_str());
                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 文件，则创建相对路径软链接到目标目录

                // 获取 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", relativePath.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));
            }
            else if (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", relativePath.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));
            }
        }
    }
}

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;
}