#include "KMRepair.h"

#include <sys/personality.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>

#ifdef USE_SECCOMP
#  include <seccomp.h>
#endif

#include "common/KMError.h"
#include "common/KMLogger.h"
#include "common/KMUtil.h"
#include "syslog.h"

/**
 * @brief 修复命令行选项
 */
class KMRepair::Options : public KMOptions
{
public:
    Options() = default;
    virtual ~Options() = default;

protected:
    /**
     * @brief 命令行参数解析后操作
     */
    void preParseHook() override;

    /**
     * @brief 命令行参数解析后操作
     */
    void postParseHook() override;

private:
    /**
     * @brief 命令行参数添加描述选项
     */
    void addOptions();

    /**
     * @brief 命令行参数检查项
     */
    void checkOptions(const opt::variables_map &varsMap);

public:
    bool m_bHelp;
    string m_sideload;
    vector<string> m_vecRefs;
};

void KMRepair::Options::preParseHook()
{
    addOptions();
}

/**
 * @brief 命令行参数解析后操作
 */
void KMRepair::Options::postParseHook()
{
    checkOptions(m_varsMap);

    if (m_bHelp)
    {
        showUsage();
        exit(EXIT_SUCCESS);
    }
}

/**
 * @brief 命令行参数添加描述选项
 */
void KMRepair::Options::addOptions()
{
    m_optionsDescription = std::make_unique<opt::options_description>(_("\nUsage:\n \tkaiming install [OPTION…] [REF…] - Repair applications or runtimes "));

    opt::options_description helpOptions(_("Help Options"));
    helpOptions.add_options()("help,h", _("Show help options"));

    opt::options_description appOptions(_("Application Options"));
    appOptions.add_options()("sideload-repo=PATH", opt::value<string>(&m_sideload), _("Use this local repo for sideloads"));

    opt::options_description positionalOptions(_("Positional Options"));
    positionalOptions.add_options()("REF...", opt::value<vector<string>>(&m_vecRefs), _("REF..."));
    m_optionsDescription->add(helpOptions).add(appOptions).add(positionalOptions);

    m_optionsPositionalDescription->add("REF...", -1);
}

/**
 * @brief 命令行参数检查项
 */
void KMRepair::Options::checkOptions(const opt::variables_map &varsMap)
{
    checkOption(varsMap, "help", "h", m_bHelp);
}

class KMRepair::Private
{
public:
    std::shared_ptr<Options> m_options;
    std::shared_ptr<KMFolder> m_folder;
    std::shared_ptr<KMRemoteSummary> m_remoteSummary;
    std::shared_ptr<KMUtil> m_util;
    std::shared_ptr<KMEnv> m_env;
    std::shared_ptr<KMParseDeploy> m_parseDeploy;
    map<string, KMRef> map_refs;
    shared_ptr<KMOSTreeHandler> ostree_handler;

    std::string m_arch;
    std::string m_remoteRepoName;
    std::string m_repoIndexUrl;
    std::string m_repoIndexLocalGzPath;
    std::string m_repoIndexLocalSubPath;

    KMCommonRef m_appRef;                  // 单独ref,用于存储到 d->m_refUserList中
    vector<KMCommonRef> m_refUserList;     // 用户输入的待修复软件列表
    vector<KMCommonRef> m_refDownloadList; // 实际上需要修复的软件列表

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

REGISTER_SUBCOMMAND_DYNCREATE(repair, KMRepair)

static vector<KMCommonRef> globalRefDownloadListForProgress;              // 实际上需要修复的软件列表,用于进度展示
static InstallCallBack globalProgressCallback;                     // 回调函数
static RepairProgressStatus installProgressStatus = { "", 0, "", 5 }; // 修复进度回调函数参数
static string progressJson = "";

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

/**
 * @brief 通过解析命令行参数获取 ref 信息
 *
 * 目前支持2种单个 ref 格式：
 *          org.kde.kclock
 *          app/org.kde.kclock/x86_64/master
 *
 * @param pref 命令行输入的appid参数，如 org.kde.kclock, app/org.kde.kclock/x86_64/master
 * @return KMCommonRef
 */
static KMCommonRef makeRefDataFromInitRefString(std::string pref)
{
    KMCommonRef ref;

    // 使用字符串流进行按"/"分割
    std::istringstream iss(pref);
    std::string token;
    std::vector<std::string> tokens;

    kmlogger.debug("Input pref:  %s", pref.c_str());

    bool onlyAppid = false;

    if (KMUtil::startsWithForRef(pref, "app/"))
    {
        kmlogger.debug("Input pref type app");
        ref.baseType = "app";
    }
    else if (KMUtil::startsWithForRef(pref, "runtime/"))
    {
        kmlogger.debug("Input pref type runtime");
        ref.baseType = "runtime";
    }
    else
    {
        kmlogger.debug("Input pref get default type");
        ref.baseType = KMUtil::getDefaultTypeForType(pref);
        onlyAppid = true;
    }

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

    if (onlyAppid)
    {
        ref.id = pref;
        globalLastId = ref.id;
        ref.arch = KMUtil::kmGetArch();
        ref.branch = KMUtil::kmGetDefaultChannel();
        ref.completedId = ref.baseType.append("/").append(ref.id).append("/").append(ref.arch).append("/").append(ref.branch);

        kmlogger.debug("complete ref string: %s", ref.completedId.c_str());
        return ref;
    }

    while (std::getline(iss, token, '/'))
    {
        kmlogger.debug("token:  %s", token.c_str());
        tokens.push_back(token);
    }

    ref.id = tokens[1];
    globalLastId = ref.id;
    ref.arch = tokens[2];
    ref.branch = tokens[3];
    ref.completedId = ref.baseType.append("/").append(ref.id).append("/").append(ref.arch).append("/").append(ref.branch);

    kmlogger.debug("complete ref string::  %s", ref.completedId.c_str());

    return ref;
}

/**
 * @brief 给出 branch, 通过解析命令行参数获取 ref 信息
 *
 * 目前支持2种单个 ref 格式：
 *          org.kde.kclock
 *          app/org.kde.kclock/x86_64/master
 *
 * @param pref 命令行输入的appid参数，如 org.kde.kclock, app/org.kde.kclock/x86_64/master
 * @return KMCommonRef
 */
static KMCommonRef makeRefDataWithBranchFromInitRefString(std::string pref, string branch)
{
    KMCommonRef ref;

    // 使用字符串流进行按"/"分割
    std::istringstream iss(pref);
    std::string token;
    std::vector<std::string> tokens;

    kmlogger.debug("Input pref:  %s", pref.c_str());

    bool onlyAppid = false;

    if (KMUtil::startsWithForRef(pref, "app/"))
    {
        kmlogger.info("Input pref type app");
        ref.baseType = "app";
    }
    else if (KMUtil::startsWithForRef(pref, "runtime/"))
    {
        kmlogger.info("Input pref type runtime");
        ref.baseType = "runtime";
    }
    else
    {
        kmlogger.info("Input pref get default type");
        ref.baseType = KMUtil::getDefaultTypeForType(pref);
        onlyAppid = true;
    }

    kmlogger.info("ref.baseType:  %s", ref.baseType.c_str());

    if (onlyAppid)
    {
        ref.id = pref;
        globalLastId = ref.id;
        ref.arch = KMUtil::kmGetArch();
        ref.branch = branch;
        ref.completedId = ref.baseType.append("/").append(ref.id).append("/").append(ref.arch).append("/").append(ref.branch);

        kmlogger.info("complete ref string: %s", ref.completedId.c_str());
        return ref;
    }

    while (std::getline(iss, token, '/'))
    {
        kmlogger.info("token:  %s", token.c_str());
        tokens.push_back(token);
    }

    ref.id = tokens[1];
    globalLastId = ref.id;
    ref.arch = tokens[2];
    ref.branch = tokens[3];
    ref.completedId = ref.baseType.append("/").append(ref.id).append("/").append(ref.arch).append("/").append(ref.branch);

    kmlogger.info("complete ref string::  %s", ref.completedId.c_str());

    return ref;
}

/**
 * @brief 根据完整的ref获取id
 *
 * @param pref
 * @return std::string
 */
static std::string getIdFromRef(string pref)
{
    // 使用字符串流进行按"/"分割
    std::istringstream iss(pref);
    std::string token;
    std::vector<std::string> tokens;

    kmlogger.info("Input pref:  %s", pref.c_str());

    bool onlyAppid = false;

    if (KMUtil::startsWithForRef(pref, "app/") || KMUtil::startsWithForRef(pref, "runtime/"))
    {
    }
    else
    {
        onlyAppid = true;
    }

    if (onlyAppid)
    {
        return pref;
    }

    while (std::getline(iss, token, '/'))
    {
        kmlogger.info("token:  %s", token.c_str());
        tokens.push_back(token);
    }

    string id = tokens[1];
    return id;
}

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

static char *formatDuration(guint64 duration)
{
    int h, m, s;

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

    if (h > 0)
    {
        return g_strdup_printf("%02d:%02d:%02d", h, m, s);
    }
    else
    {
        return g_strdup_printf("%02d:%02d", m, s);
    }
}

/**
 * @brief 更新进度信息
 *
 */
static void updateInstallProgress()
{
    // 只有当 globalProgressCallback 是有效的时候才调用,即已经与某个可调用对象关联，并且没有被释放，避免 bad_function_call
    if (globalProgressCallback && progressJson != "")
    {
        globalProgressCallback(progressJson);
    }
}

static map<string, guint64> getAllRefsMap(string completedRef, guint64 &singleSize, guint64 &totalSize)
{
    map<string, guint64> refsMap;

    for (auto &ref : globalRefDownloadListForProgress)
    {
        kmlogger.info("completedId: %s", ref.completedId.c_str());
        guint64 installedSize;
        if (ref.baseType == "app")
        {
            installedSize = ref.installedSizeInt;
        }
        else
        {
            installedSize = ref.downloadSize;
        }
        ref.realInstalledSize = installedSize;

        if (completedRef == ref.completedId)
        {
            singleSize = ref.realInstalledSize;
        }

        totalSize += installedSize;
        refsMap[ref.completedId] = installedSize;
    }

    return refsMap;
}

static map<string, guint64> getAllRefsMap(guint64 &totalSize)
{
    map<string, guint64> refsMap;

    for (auto &ref : globalRefDownloadListForProgress)
    {
        // kmlogger.info("completedId: %s", ref.completedId.c_str());
        guint64 installedSize;
        if (ref.baseType == "app")
        {
            installedSize = ref.installedSizeInt;
        }
        else
        {
            installedSize = ref.downloadSize;
        }
        ref.realInstalledSize = installedSize;

        totalSize += installedSize;
        refsMap[ref.completedId] = installedSize;
    }

    return refsMap;
}

static bool isZero(double value, double tolerance = 1e-6)
{
    return std::abs(value) < tolerance;
}

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

    kmlogger.info("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.info("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.info("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.info("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.info("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;
}

/**
 * @brief 进度处理回调函数
 *
 * 进度条处理分成3个步骤：
 *  - 1. 当拉取 metadata 时， 增长到 5%;
 *  - 2. 下载数据一直到 97%;
 *  - 3. 写入 ostree objects 为最后的 3%
 *
 * @param progressStatus 在 ostree pull 时，发送的进度等信息结构体
 */
static void installProgressCallback(ProgressStatus progressStatus)
{
    kmlogger.info("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.info("elapsedTime: %ld", elapsedTime);

    if (*progressStatus.ostreeStatus)
    {
        // 当ostree_status 有反馈，则代表fetch成功，总进度到了100%
        kmlogger.info("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.info("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.info("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.info("下载额外数据 buf: %s", buf);

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

            /* 下载总进度到达 97% */
            if (total > 0)
            {
                newProgress = 5 + ((totalTransferred / (gdouble)total) * 92);
            }
            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.info("totalTransferred: %ld elapsedTime: %ld buf: %s", totalTransferred, elapsedTime, buf);
        }

        if (newProgress < progressStatus.progress && progressStatus.lastTotal == total)
        {
            newProgress = progressStatus.progress;
        }

        progressStatus.lastTotal = total;
        kmlogger.info("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; // 单一软件包下载进度
    guint totalPercent;                 // 所有包下载总进度

    guint64 totalSize = 0;
    guint64 singleSize = 0;
    map<string, guint64> installRefsMap = getAllRefsMap(progressStatus.ref, singleSize, totalSize);
    string currentRef = getIdFromRef(progressStatus.ref);

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

    for (const auto &item : globalRefDownloadListForProgress) // 内部排序，因此不能顺序存储
    {
        kmlogger.info("completedId: %s size:%ld ", item.completedId.c_str(), item.realInstalledSize);
        if (item.completedId == progressStatus.ref)
        {
            currentProgress += (double)singlePercent / 100 * singleSize;
            break;
        }
        currentProgress += item.realInstalledSize;
    }

    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 speedLen = 0;

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

        guint64 remainingBytes = totalSize - currentProgress;
        string remainingStr = calculateDownloadTime(string(formattedBytesSec), remainingBytes).c_str();
        kmlogger.info("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());
        speedLen = MAX(speedLen, 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 ", "正在修复 ", currentRef.c_str());

    kmlogger.info("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.info("str: %s", str);
        i++;
    }

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

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

    printf("%s", str);
    lastOutput = string(str);

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

    kmlogger.info("repair progress >>:  refId:%s progress:%d ", installProgressStatus.refId.c_str(), installProgressStatus.progress);

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

KMRepair::KMRepair()
    : d(std::make_unique<Private>())
{
    init();
}

KMRepair::~KMRepair() { }

int KMRepair::despose(int argc, char **argv)
{
    vector<string> vecList;
    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] != '-')
        {
            vecList.push_back(argv[i]);
        }
        else if (vecList.size() > 0)
        {
            kmlogger.error("args error");
            return KM_ERROR_INVALID_ARGS;
        }
    }

    // setenv("G_MESSAGES_DEBUG", "all", 1);

    init();

    // 参数解析
    d->m_options->parseCommandLine(argc, argv);

    if (vecList.size() > 1 || vecList.empty())
    {
        kmlogger.error("Args number error, not support args.");
        printf("%s\n", _("Args number error, not support args."));
        return KM_ERROR_INVALID_ARGS;
    }

    int ret = repair(vecList[0]);

    return EXIT_SUCCESS;
}

/**
 * @brief 开始对已获取的用户软件包列表执行修复
 *
 * @param vecName
 * @return int
 */
int KMRepair::start(const vector<string> &vecName)
{
    if (!d->m_env->passEnvCheck())
    {
        kmlogger.error("Failed to check environments!");
        return KM_ERROR_CHECK_ENV_FAILED;
    }

    d->m_folder->ensureRepoForSudo(false);
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo
    KMOSTreeHandler ostreeManager(repoPath.string());

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

    if (!d->m_options->m_sideload.empty())
    {
        return offlineInstall(vecName);
    }

    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);

    string summaryUrl = string(ostreeRepoUrl).append("/").append("summary.idx");
    d->m_remoteRepoName = std::string(REPO_NAME);
    string summaryIdxPath = d->m_folder->getSummariesIdxPath(d->m_remoteRepoName).u8string();

    // Curl 下载 summary.idx
    if (!d->m_remoteSummary->curlApiDownload(summaryUrl, summaryIdxPath))
    {
        kmlogger.error("Curl download failed. SummaryUrl:  %s  Store summary.idx to SummaryIdxPath: %s", summaryUrl.c_str(), summaryIdxPath.c_str());
        std::cout << _("Curl download summary file failed!") << std::endl;
        return KM_ERROR_CURL_DOWNLOAD_FAILED;
    }

    // 根据summary.idx 获取 index
    string index;
    if (!d->m_remoteSummary->parseSummaryIdxFromPath(summaryIdxPath, index))
    {
        kmlogger.error("Get commit from summary.idx failed!");
        return KM_ERROR_GET_SUMMARY_COMMIT_FAILED;
    }
    kmlogger.info("Get index from summary.idx :  %s", index.c_str());

    d->m_arch = d->m_util->kmGetArch();
    kmlogger.info("Arch:  %s", d->m_arch.c_str());

    d->m_repoIndexUrl = ostreeRepoUrl + string("/summaries/") + index + string(".gz");
    kmlogger.info("Need to curl .gz file :  %s", d->m_repoIndexUrl.c_str());

    d->m_repoIndexLocalGzPath = d->m_folder->getSummariesIndexGzPath(d->m_remoteRepoName, d->m_arch, index);
    kmlogger.info("Local .gz file :  %s", d->m_repoIndexLocalGzPath.c_str());

    if (!d->m_remoteSummary->curlApiDownloadBinaryGZFile(d->m_repoIndexUrl, d->m_repoIndexLocalGzPath))
    {
        kmlogger.error("Download .gz file failed.");

        std::cout << _("Curl download binary summary file failed!") << std::endl;

        return KM_ERROR_CURL_DOWNLOAD_FAILED;
    }

    d->m_repoIndexLocalSubPath = d->m_folder->getSummariesIndexGzSubPath(d->m_remoteRepoName, d->m_arch, index);
    kmlogger.info("Local .sub file :  %s", d->m_repoIndexLocalSubPath.c_str());

    // 获取仓库清单文件: kaiming-repo-x86_64-eda00c3fd4a65f6f2032d28e7cc0c623e5f073b0627d7208c13fe1a0fcd41ab4.sub
    if (!d->m_remoteSummary->decompressGzFile(d->m_repoIndexLocalGzPath, d->m_repoIndexLocalSubPath))
    {
        kmlogger.error("Decompression .gz file failed.");
        return KM_ERROR_DECOMPRESSION_FAILED;
    }

    GVariant *subsummary = d->m_remoteSummary->getSummaryFromPath(d->m_repoIndexLocalSubPath);
    if (!subsummary)
    {
        kmlogger.error("Get GVariant pointer data failed!");
        return KM_ERROR_GET_SUBSUMMARY_GVARIANT_FAILED;
    }

    char *ref; // "app/org.kde.kclock/x86_64/master";
    VarRefInfoRef info;
    char *checksum = NULL;
    GBytes *metadataBytes = NULL;
    guint64 downloadSize = 0;
    guint64 installedSize = 0;
    const char *metadata = NULL;
    VarMetadataRef sparseCache;
    char *summaryChecksum = NULL;
    KMCommonRef downloadRuntime;

    // 对用户要求下载的软件列表逐一处理,从而获取到最终包括软件包和对应运行时的软件列表
    for (auto &name : vecName)
    {
        kmlogger.info("Repair app %s", name.c_str());
        d->m_appRef.pref = name;
        d->m_appRef = makeRefDataFromInitRefString(d->m_appRef.pref);
        d->m_appRef.summaryIdxPath = summaryIdxPath;
        d->m_appRef.repoSummaryPath = d->m_repoIndexLocalSubPath;
        d->m_appRef.subsummary = subsummary;

        bool isInstalled = currentRefIsInstalled(d->m_appRef);
        if (isInstalled)
        {
            kmlogger.info("当前软件包 %s 在修复过程中未卸载成功,不进行修复", name.c_str());
            // cout << _("Current ") << name << _(" has been installed!") << std::endl;
            continue;
        }

        // 删除软件包所在目录 /opt/kaiming/app/refId
        // kmlogger.info("remove app %s install dir", name.c_str());
        // if (!fs::remove_all(d->m_folder->getAppPath() / name))
        // {
        //     kmlogger.error("repair %s error, can\'t delete the directory.", name);
        //     return KM_ERROR_DELETE_DIRECTORY_FAILED;
        // }

        kmlogger.info("开始在远程仓库中查找 ref 对应的 commitid ...");
        // runtime/top.openkylin.Platform/x86_64/{0.4, 0.5} to get: runtime/top.openkylin.Platform/x86_64
        string matchRef = KMUtil::removeLastPartWithDelimiter(d->m_appRef.completedId);
        kmlogger.info("Match pattern: %s", matchRef.c_str());

        if (!d->m_remoteSummary->findRefVectorFromRemoteSummary(d->m_appRef.subsummary, NULL, matchRef, d->m_appRef.matchRefs))
        {
            kmlogger.error("No find this ref: %s", name.c_str());
            std::cout << _("Not find this ref ") << name << std::endl;
            return KM_ERROR_REF_NOT_FOUND;
        }

        if (!d->m_appRef.matchRefs.empty())
        {
            for (auto &mref : d->m_appRef.matchRefs)
            {
                kmlogger.info("matchRefs: %s", mref.c_str());
            }
        }

        // 有且只有一个ref.  通过 API, -y 则应该默认全修复运行时,否则会出现运行时和运用匹配不上
        kmlogger.info("For API callback or -y option.");
        int i = 0;
        for (auto &id : d->m_appRef.matchRefs)
        {
            d->m_appRef.completedId = d->m_appRef.matchRefs[i]; // 对于stable,但默认是branch情况,需要重新赋值.
            d->m_relatedRefs.push(d->m_appRef.completedId);     // app/org.kde.kclock/x86_64/{master, stable}
            ref = (char *)d->m_appRef.matchRefs[i].c_str();     // 只对一个 ref
            kmlogger.info("Default ref: %s", ref);

            i++;
        }

        kmlogger.info("Need install ref id: %s", ref);
        if (d->m_appRef.subsummary == NULL || !d->m_remoteSummary->summaryLookupRefCommitAndInfo(d->m_appRef.subsummary, NULL, ref, &checksum, &d->m_appRef.info))
        {
            kmlogger.error("Not found this ref commit : %s", ref);
            return KM_ERROR_REF_COMMIT_NOT_FOUND;
        }

        d->m_appRef.commit = string(checksum, checksum + strlen(checksum));
        kmlogger.info("Ref <completedId : commit>:  <%s : %s>", d->m_appRef.completedId.c_str(), d->m_appRef.commit.c_str());

        kmlogger.info("开始查找ref相关的信息...");

        // 获取当前 ref 的相关信息
        if (!d->m_remoteSummary->summaryRemoteStateLookupCache(d->m_appRef.subsummary, ref, &downloadSize, &installedSize, &metadata))
        {
            kmlogger.error("Not get info from this ref: %s", ref);
            return KM_ERROR_GET_REF_INFO_FAILED;
        }
        d->m_appRef.applicationInfo = string(metadata, metadata + strlen(metadata));
        d->m_appRef.remote = REPO_NAME;
        // kmlogger.debug("Ref <Id : ApplicationInfo>:  <%s : %s>", d->m_appRef.completedId.c_str(), d->m_appRef.applicationInfo.c_str());

        downloadRuntime.subsummary = d->m_appRef.subsummary;

        d->m_appRef.metadata = d->m_appRef.applicationInfo;
        d->m_appRef.installedSizeInt = installedSize;
        d->m_appRef.downloadSize = downloadSize;
        d->m_appRef.summaryMetadata = varMetadataDupToGvariant(varRefInfoGetMetadata(d->m_appRef.info));

        d->m_appRef.refApplication.command = getValueByGroupAndKeyFromKVData(d->m_appRef.metadata, "Application", "command"); // top.openkylin.Platform/x86_64/0.5
        kmlogger.info("Ref Application Command: %s", d->m_appRef.refApplication.command.c_str());

        d->m_appRef.runtime = getRuntimeFromRef(d->m_appRef);
        downloadRuntime.defaultRuntimeBranch = getDefaultRuntimeVersionRef(d->m_appRef);
        kmlogger.info("default runtime branch:  %s", downloadRuntime.defaultRuntimeBranch.c_str());

        d->m_appRef.defaultRuntimeBranch = getDefaultAppVersionRef(d->m_appRef);
        kmlogger.info("default app branch:  %s", d->m_appRef.defaultRuntimeBranch.c_str());

        kmlogger.info("开始查找运行时...");

        // ref = "runtime/org.kde.haruna.Locale/x86_64/master";
        d->m_relatedRefs.push(d->m_appRef.runtime);
        d->m_refUserList.push_back(d->m_appRef);
    }

    list<string> relatedRefsList;

    // 打印获取的用户列表
    while (!d->m_relatedRefs.empty())
    {
        string currentRef = d->m_relatedRefs.top();
        relatedRefsList.push_front(currentRef);
        kmlogger.info("d->relatedRefs: %s", currentRef.c_str());
        d->m_relatedRefs.pop();
    }

    // set 是一个自动排序容器,只存储唯一值,也可以搭配 sort, unique来进行删除重复项
    set<string> relatedRefSet(relatedRefsList.begin(), relatedRefsList.end());
    relatedRefsList.assign(relatedRefSet.begin(), relatedRefSet.end());

    if (relatedRefsList.empty())
    {
        printf("%s\n", _("This app has been repaired!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }

    for (auto &ref : relatedRefsList)
    {
        kmlogger.info("relatedRefList: %s", ref.c_str());
    }

    // 先遍历依赖的运行时依赖，再遍历应用或当前运行时本身依赖
    // while (!d->m_relatedRefs.empty())
    list<string>::iterator itRef;
    for (itRef = relatedRefsList.begin(); itRef != relatedRefsList.end(); itRef++)
    {
        // string currentRef = d->m_relatedRefs.top();
        string currentRef = *itRef;
        kmlogger.info("Current Ref: %s", currentRef.c_str());

        string baseType = getBaseTypeFromRef(currentRef);
        if (baseType == "runtime")
        {
            ref = currentRef.data();
            char *runtimeChecksum = NULL;
            kmlogger.info("runtime ref: %s", ref);
            if (downloadRuntime.subsummary == NULL || !d->m_remoteSummary->summaryLookupRefCommitAndInfo(downloadRuntime.subsummary, NULL, ref, &runtimeChecksum, &downloadRuntime.info))
            {
                kmlogger.error("Not found this ref commit : %s", ref);
                // d->m_relatedRefs.pop();
                continue;
            }

            downloadRuntime.commit = string(runtimeChecksum, runtimeChecksum + strlen(runtimeChecksum));
            downloadRuntime.remote = REPO_NAME;
            downloadRuntime.completedId = currentRef;
            kmlogger.info("runtime ref info=> id:  %s commit: %s", currentRef.c_str(), downloadRuntime.commit.c_str());

            // 获取当前 ref 的相关信息
            if (!d->m_remoteSummary->summaryRemoteStateLookupCache(downloadRuntime.subsummary, ref, &downloadSize, &installedSize, &metadata))
            {
                kmlogger.error("Not get info from this ref  %s", ref);
                return KM_ERROR_GET_REF_INFO_FAILED;
            }
            downloadRuntime.installedSize = installedSize;
            downloadRuntime.downloadSize = downloadSize;
            downloadRuntime.applicationInfo = string(metadata, metadata + strlen(metadata));
            // kmlogger.debug("runtime ref id:   %s applicationInfo: %s", ref, downloadRuntime.applicationInfo.c_str());

            kmlogger.info("开始查找其他相关依赖关系...");

            getDownloadRefsList(downloadRuntime, downloadRuntime.applicationInfo.data());

            d->m_refDownloadList.push_back(downloadRuntime);
            // d->m_relatedRefs.pop();
        }
        else
        {
            // 遍历应用本身依赖
            kmlogger.info("开始查找其他相关依赖关系...");

            for (auto &refUserList : d->m_refUserList)
            {
                if (refUserList.completedId == currentRef)
                {
                    kmlogger.info("Match ref : %s", currentRef.c_str());
                    getDownloadRefsList(refUserList, refUserList.applicationInfo.data());
                    d->m_refDownloadList.push_back(refUserList);
                    // d->m_relatedRefs.pop();
                }
            }
        }
    }

    // Todo: need check list
    kmlogger.info("列出待处理的refs列表...");
    if (d->m_refDownloadList.empty())
    {
        printf("%s\n", _("This app has been repaired!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }
    for (auto &downloadRef : d->m_refDownloadList)
    {
        kmlogger.info("completedId:   %s commit: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());
    }

    for (auto &downloadRef : d->m_refDownloadList)
    {
        kmlogger.info("completedId:   %s commit: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());
        bool isInstalled = currentRefIsInstalled(downloadRef);
        if (isInstalled)
        {
            kmlogger.info("当前软件包 %s 已修复", downloadRef.completedId.c_str());
            downloadRef.hasDownload = true;
            downloadRef.autoDelete = true;
        }
        else
        {
            if (downloadRef.completedId.find(".Debug") != std::string::npos)
            {
                kmlogger.info("当前软件包 %s 属于Debug,不需要修复", downloadRef.completedId.c_str());
                downloadRef.autoDelete = true;
            }
            kmlogger.info("当前软件包 %s 需要修复", downloadRef.completedId.c_str());
        }
    }

    // 使用 remove_if 结合 lambda 表达式删除匹配的值
    d->m_refDownloadList.erase(std::remove_if(d->m_refDownloadList.begin(),
                                              d->m_refDownloadList.end(),
                                              [&](const KMCommonRef &ref)
                                              {
                                                  return ref.autoDelete;
                                              }),
                               d->m_refDownloadList.end());

    kmlogger.info("列出待修复的refs列表...");
    vector<string> refs;
    if (d->m_refDownloadList.empty())
    {
        printf("%s\n", _("This app has been repaired!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }

    int indexDownloadRef = 0;
    // printf("\n%-5s %-50s %-20s %-10s %-20s %-20s\n", _(""), _("ID"), _("Branch"), _("Type"), _("Remote"), _("Size"));

    globalRefDownloadListForProgress.clear();
    refs.clear();

    /* 去除重复项，避免商店安装的包在重复部署中段错误导致 system dbus 失败所引起的一系列错误：
     * 1) 商店卸载后再次安装进度一直在，关闭商店后可以显示已经安装成功；
     * 2) 检测可更新、可安装、信息获取等接口失败，导致商店更新列表为空
     */
    std::unordered_set<string> seen; // 去除重复项

    for (auto &downloadRef : d->m_refDownloadList)
    {
        kmlogger.info("当前软件包是否需要修复=> [completedId]: %s [commit]: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());

        if (seen.find(downloadRef.completedId) != seen.end()) // 找到重复项
        {
            continue;
        }

        kmlogger.info("当前软件包需要修复=> [completedId]: %s [commit]: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());

        globalRefDownloadListForProgress.push_back(downloadRef);
        seen.insert(downloadRef.completedId);
        indexDownloadRef++;

        // printRefInfo(downloadRef, indexDownloadRef);
        refs.push_back(downloadRef.completedId);
    }

    d->m_refDownloadList.clear();
    for (auto realDownloadRef : globalRefDownloadListForProgress)
    {
        kmlogger.info("当前软件包需要修复=>>>>>>>>>> [completedId]: %s [commit]: %s", realDownloadRef.completedId.c_str(), realDownloadRef.commit.c_str());
        d->m_refDownloadList.push_back(realDownloadRef);
    }

    for (auto &ref : refs)
    {
        kmlogger.info("当前软件包 %s 需要修复", ref.c_str());
    }

    ostreeManager.pull(REPO_NAME, refs, installProgressCallback);

    return deploy(ostreeManager);
}

/**
 * @brief 开始对已获取的用户软件包列表执行修复
 * @param vecRef
 * @return int
 */
int KMRepair::offlineInstall(const vector<string> &vecRef)
{
    // TODO: 现为预防影响正常修复流程，暂独立一个函数
    // TODO: 后期需与instalh函数优化整合
    fs::path repoPath = d->m_folder->getRepoPath(); // /opt/kaiming/repo
    KMOSTreeHandler ostreeManager(repoPath.string());
    string ostreeRepoUrl = ostreeManager.getRemoteUrl(REPO_NAME);

    // TODO: remote 如何获取,暂时写死
    string collectionId = "kylin.kaiming.export";

    d->m_arch = d->m_util->kmGetArch();
    kmlogger.info("Arch:  %s", d->m_arch.c_str());

    string repoSummaryPath = d->m_options->m_sideload + "/summary";
    GVariant *subsummary = d->m_remoteSummary->getSummaryFromPath(repoSummaryPath);
    if (!subsummary)
    {
        kmlogger.error("Get GVariant pointer data failed!");
        std::cout << "Get gvariant pointer data failed, please check the sideload path!" << endl;
        return KM_ERROR_GET_SUBSUMMARY_GVARIANT_FAILED;
    }

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

    char *ref; // "app/org.kde.kclock/x86_64/master";
    VarRefInfoRef info;
    char *checksum = NULL;
    GBytes *metadataBytes = NULL;
    guint64 downloadSize = 0;
    guint64 installedSize = 0;
    const char *metadata = NULL;
    VarMetadataRef sparseCache;
    char *summaryChecksum = NULL;
    KMCommonRef downloadRuntime;

    // 对用户要求下载的软件列表逐一处理,从而获取到最终包括软件包和对应运行时的软件列表
    for (auto &name : vecRef)
    {
        kmlogger.info("Repair app %s", name.c_str());
        d->m_appRef.pref = name;
        d->m_appRef = makeRefDataFromInitRefString(d->m_appRef.pref);
        d->m_appRef.repoSummaryPath = repoSummaryPath;
        d->m_appRef.subsummary = subsummary;
        d->m_appRef.remote = REPO_NAME;

        bool isInstalled = currentRefIsInstalled(d->m_appRef);
        if (isInstalled)
        {
            kmlogger.info("当前软件包 %s 已修复", name.c_str());
            // cout << _("Current ") << name << _(" has been installed!") << std::endl;
            continue;
        }

        kmlogger.info("开始在远程仓库中查找 ref 对应的 commitid ...");
        // runtime/top.openkylin.Platform/x86_64/{0.4, 0.5} to get: runtime/top.openkylin.Platform/x86_64
        string matchRef = KMUtil::removeLastPartWithDelimiter(d->m_appRef.completedId);
        kmlogger.info("Match pattern: %s", matchRef.c_str());

        if (!d->m_remoteSummary->findRefVectorFromRemoteSummary(d->m_appRef.subsummary, collectionId.c_str(), matchRef, d->m_appRef.matchRefs))
        {
            kmlogger.error("No find this ref: %s", name.c_str());
            std::cout << _("Not find this ref ") << name << std::endl;
            return KM_ERROR_REF_NOT_FOUND;
        }

        // 通过 API, -y 则应该默认全修复
        for (auto &id : d->m_appRef.matchRefs)
        {
            relatedRefs.push(d->m_appRef.completedId); // app/org.kde.kclock/x86_64/{master, stable}
        }

        kmlogger.info("Need install ref id: %s", ref);
        if (d->m_appRef.subsummary == NULL || !d->m_remoteSummary->summaryLookupRefCommitAndInfo(d->m_appRef.subsummary, collectionId.c_str(), ref, &checksum, &d->m_appRef.info))
        {
            kmlogger.error("Not found this ref commit : %s", ref);
            return KM_ERROR_REF_COMMIT_NOT_FOUND;
        }

        d->m_appRef.summaryMetadata = varMetadataDupToGvariant(varRefInfoGetMetadata(d->m_appRef.info));
        d->m_appRef.commit = string(checksum, checksum + strlen(checksum));
        kmlogger.info("Ref <completedId : commit>:  <%s : %s>", d->m_appRef.completedId.c_str(), d->m_appRef.commit.c_str());

        kmlogger.info("开始查找ref相关的信息...");

        // 获取当前 ref 的相关信息
        if (!d->m_remoteSummary->summaryRemoteStateLookupCache(d->m_appRef.subsummary, ref, &downloadSize, &installedSize, &metadata))
        {
            KMOSTreeHandler sideOstreeManager(d->m_options->m_sideload);
            g_autoptr(GVariant) pCommitdata = sideOstreeManager.getCommitData(d->m_appRef.commit);
            if (!d->m_remoteSummary->summarySideloadRemoteState(pCommitdata, &downloadSize, &installedSize, &metadata))
            {
                kmlogger.error("Not get info from this ref: %s", ref);
                return KM_ERROR_GET_REF_INFO_FAILED;
            }
        }
        d->m_appRef.applicationInfo = string(metadata, metadata + strlen(metadata));
        kmlogger.info("Ref <Id : ApplicationInfo>:  <%s : %s>", d->m_appRef.completedId.c_str(), d->m_appRef.applicationInfo.c_str());

        downloadRuntime.subsummary = d->m_appRef.subsummary;

        d->m_appRef.metadata = d->m_appRef.applicationInfo;
        d->m_appRef.installedSizeInt = installedSize;
        d->m_appRef.downloadSize = downloadSize;

        d->m_appRef.refApplication.command = getValueByGroupAndKeyFromKVData(d->m_appRef.metadata, "Application", "command"); // top.openkylin.Platform/x86_64/0.5
        kmlogger.info("Ref Application Command: %s", d->m_appRef.refApplication.command.c_str());

        d->m_appRef.runtime = getRuntimeFromRef(d->m_appRef);
        downloadRuntime.defaultRuntimeBranch = getDefaultRuntimeVersionRef(d->m_appRef);
        kmlogger.info("default runtime branch:  %s", downloadRuntime.defaultRuntimeBranch.c_str());

        d->m_appRef.defaultRuntimeBranch = getDefaultAppVersionRef(d->m_appRef);
        kmlogger.info("default app branch:  %s", d->m_appRef.defaultRuntimeBranch.c_str());

        kmlogger.info("开始查找运行时...");

        // ref = "runtime/org.kde.haruna.Locale/x86_64/master";
        relatedRefs.push(d->m_appRef.runtime);
        d->m_refUserList.push_back(d->m_appRef);
    }

    list<string> relatedRefsList;

    // 打印获取的用户列表
    while (!relatedRefs.empty())
    {
        string currentRef = relatedRefs.top();
        relatedRefsList.push_front(currentRef);
        kmlogger.info("relatedRefs: %s", currentRef.c_str());
        relatedRefs.pop();
    }

    // set 是一个自动排序容器,只存储唯一值,也可以搭配 sort, unique来进行删除重复项
    set<string> relatedRefSet(relatedRefsList.begin(), relatedRefsList.end());
    relatedRefsList.assign(relatedRefSet.begin(), relatedRefSet.end());

    if (relatedRefsList.empty())
    {
        printf("%s\n", _("This app has been repaired!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }
    for (auto &ref : relatedRefsList)
    {
        kmlogger.info("relatedRefList: %s", ref.c_str());
    }

    // 先遍历依赖的运行时依赖，再遍历应用或当前运行时本身依赖
    // while (!relatedRefs.empty())
    list<string>::iterator itRef;
    for (itRef = relatedRefsList.begin(); itRef != relatedRefsList.end(); itRef++)
    {
        // string currentRef = relatedRefs.top();
        string currentRef = *itRef;
        kmlogger.info("Current Ref: %s", currentRef.c_str());

        string baseType = getBaseTypeFromRef(currentRef);
        if (baseType == "runtime")
        {
            ref = currentRef.data();
            char *runtimeChecksum = NULL;
            kmlogger.info("runtime ref: %s", ref);
            if (downloadRuntime.subsummary == NULL || !d->m_remoteSummary->summaryLookupRefCommitAndInfo(downloadRuntime.subsummary, collectionId.c_str(), ref, &runtimeChecksum, &downloadRuntime.info))
            {
                kmlogger.error("Not found this ref commit : %s", ref);
                // relatedRefs.pop();
                continue;
            }

            downloadRuntime.commit = string(runtimeChecksum, runtimeChecksum + strlen(runtimeChecksum));
            downloadRuntime.remote = REPO_NAME;
            downloadRuntime.completedId = currentRef;
            kmlogger.info("runtime ref info=> id:  %s commit: %s", currentRef.c_str(), downloadRuntime.commit.c_str());

            // 获取当前 ref 的相关信息
            if (!d->m_remoteSummary->summaryRemoteStateLookupCache(downloadRuntime.subsummary, ref, &downloadSize, &installedSize, &metadata))
            {
                KMOSTreeHandler sideOstreeManager(d->m_options->m_sideload);
                g_autoptr(GVariant) pCommitdata = sideOstreeManager.getCommitData(downloadRuntime.commit);
                if (!d->m_remoteSummary->summarySideloadRemoteState(pCommitdata, &downloadSize, &installedSize, &metadata))
                {
                    kmlogger.error("Not get info from this ref: %s", ref);
                    return KM_ERROR_GET_REF_INFO_FAILED;
                }
            }
            downloadRuntime.installedSize = installedSize;
            downloadRuntime.downloadSize = downloadSize;
            downloadRuntime.applicationInfo = string(metadata, metadata + strlen(metadata));
            kmlogger.info("runtime ref id:   %s applicationInfo: %s", ref, downloadRuntime.applicationInfo.c_str());

            kmlogger.info("开始查找其他相关依赖关系...");

            getSideloadRefsList(downloadRuntime, downloadRuntime.applicationInfo.data(), collectionId);

            d->m_refDownloadList.push_back(downloadRuntime);
            // relatedRefs.pop();
        }
        else
        {
            // 遍历应用本身依赖
            kmlogger.info("开始查找其他相关依赖关系...");

            for (auto &refUserList : d->m_refUserList)
            {
                if (refUserList.completedId == currentRef)
                {
                    kmlogger.info("Match ref : %s", currentRef.c_str());
                    getSideloadRefsList(refUserList, refUserList.applicationInfo.data(), collectionId);
                    d->m_refDownloadList.push_back(refUserList);
                    // relatedRefs.pop();
                }
            }
        }
    }

    // Todo: need check list
    kmlogger.info("列出待处理的refs列表...");
    if (d->m_refDownloadList.empty())
    {
        printf("%s\n", _("This app has been repaired!"));
        return KM_ERROR_ALREADY_INSTALLED;
    }
    for (auto &downloadRef : d->m_refDownloadList)
    {
        kmlogger.info("completedId:   %s commit: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());
    }

    for (auto &downloadRef : d->m_refDownloadList)
    {
        kmlogger.info("completedId:   %s commit: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());
        bool isInstalled = currentRefIsInstalled(downloadRef);
        if (isInstalled)
        {
            kmlogger.info("当前软件包 %s 已修复", downloadRef.completedId.c_str());
            downloadRef.hasDownload = true;
            downloadRef.autoDelete = true;
        }
        else
        {
            if (downloadRef.completedId.find(".Debug") != std::string::npos)
            {
                kmlogger.info("当前软件包 %s 属于 Debug，不需要修复", downloadRef.completedId.c_str());
                downloadRef.autoDelete = true;
            }
            else if (downloadRef.completedId.find(".Sources") != std::string::npos)
            {
                kmlogger.info("当前软件包 %s 属于 Sources，不需要修复", downloadRef.completedId.c_str());
                downloadRef.autoDelete = true;
            }
            kmlogger.info("当前软件包 %s 需要修复", downloadRef.completedId.c_str());
        }
    }

    // 使用 remove_if 结合 lambda 表达式删除匹配的值
    d->m_refDownloadList.erase(std::remove_if(d->m_refDownloadList.begin(),
                                              d->m_refDownloadList.end(),
                                              [&](const KMCommonRef &ref)
                                              {
                                                  return ref.autoDelete;
                                              }),
                               d->m_refDownloadList.end());

    kmlogger.info("列出待修复的refs列表...");
    vector<string> refs;

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

    int indexDownloadRef = 0;
    // printf("\n%-5s %-50s %-20s %-10s %-20s %-20s\n", _(""), _("ID"), _("Branch"), _("Type"), _("Remote"), _("Size"));

    globalRefDownloadListForProgress.clear();
    refs.clear();

    /* 去除重复项，避免商店安装的包在重复部署中段错误导致 system dbus 失败所引起的一系列错误：
     * 1) 商店卸载后再次安装进度一直在，关闭商店后可以显示已经安装成功；
     * 2) 检测可更新、可安装、信息获取等接口失败，导致商店更新列表为空
     */
    std::unordered_set<string> seen; // 去除重复项

    for (auto &downloadRef : d->m_refDownloadList)
    {
        kmlogger.info("当前软件包是否需要修复=> [completedId]: %s [commit]: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());

        if (seen.find(downloadRef.completedId) != seen.end()) // 找到重复项
        {
            continue;
        }

        kmlogger.info("当前软件包需要修复=> [completedId]: %s [commit]: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());

        globalRefDownloadListForProgress.push_back(downloadRef);
        seen.insert(downloadRef.completedId);
        indexDownloadRef++;

        // printRefInfo(downloadRef, indexDownloadRef);
        refs.push_back(downloadRef.completedId);
    }

    d->m_refDownloadList.clear();
    for (auto realDownloadRef : globalRefDownloadListForProgress)
    {
        kmlogger.info("当前软件包需要修复=>>>>>>>>>> [completedId]: %s [commit]: %s", realDownloadRef.completedId.c_str(), realDownloadRef.commit.c_str());
        d->m_refDownloadList.push_back(realDownloadRef);
    }

    for (auto &ref : refs)
    {
        kmlogger.info("当前软件包 %s 需要修复", ref.c_str());
    }

    for (auto &downloadRef : d->m_refDownloadList)
    {
        GVariantBuilder builder;
        g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
        GVariantBuilder colrefBbuilder;
        g_variant_builder_init(&colrefBbuilder, G_VARIANT_TYPE("a(sss)"));
        g_variant_builder_add(&colrefBbuilder, "(sss)", collectionId.c_str(), downloadRef.completedId.c_str(), downloadRef.commit.c_str());
        g_variant_builder_add(&builder, "{s@v}", "collection-refs", g_variant_new_variant(g_variant_builder_end(&colrefBbuilder)));
        g_variant_builder_add(&builder, "{s@v}", "override-remote-name", g_variant_new_variant(g_variant_new_string("kaiming-repo")));
        g_autoptr(GVariant) options = g_variant_ref_sink(g_variant_builder_end(&builder));

        ostreeManager.pullWithOptions("file://" + d->m_options->m_sideload, downloadRef.completedId, options, installProgressCallback);
    }

    return deploy(ostreeManager);
}

/**
 * @brief 部署数据
 *
 * @return
 *   KM_ERROR_NO 成功
 *   其他值 失败
 */
int KMRepair::deploy(KMOSTreeHandler &ostreeManager)
{
    kmlogger.info("部署开始");
    // 这里需要去重，一旦有重复则会重复创建软链接失败导致段错误，让 system dbus 崩溃
    for (auto &downloadRef : d->m_refDownloadList)
    {
        fs::path basePath = d->m_folder->getPath();
        kmlogger.info("completedId:  %s commit: %s", downloadRef.completedId.c_str(), downloadRef.commit.c_str());
        fs::path commitDataPath = basePath / downloadRef.completedId / downloadRef.commit;
        kmlogger.info("commitDataPath:  %s", commitDataPath.c_str());

        if (std::filesystem::exists(commitDataPath) || std::filesystem::create_directories(commitDataPath))
        {
            kmlogger.info("Directory created or already exists successfully!");
        }
        else
        {
            kmlogger.info("Directory already exists or creation failed.");
        }

        // Create symbolic link for commitDataPath
        // 创建相对路径软链接
        fs::path commitDataSymbolicPath = basePath / downloadRef.completedId / "active";
        std::string relativeActivePath = fs::relative(commitDataPath, commitDataSymbolicPath.parent_path()).string();
        kmlogger.info("relativeActivePath:  %s", relativeActivePath.c_str());

        // 软链接存在则不处理
        if (!fs::exists(commitDataSymbolicPath))
        {
            fs::create_symlink(fs::path(relativeActivePath), commitDataSymbolicPath);
        }

        // ostreeManager.checkout("f3b1314b51f2b8865089f13cbae5b7cd449b169f0b36530d27da74beb68aa492",  "/home/ysq/test-install/app");
        // ostreeManager.checkout(downloadRef.commit, commitDataPath.string(), "metadata"); // export/files不存在
        ostreeManager.checkout(downloadRef.commit, commitDataPath.string());

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

        kmlogger.info("baseType:  %s", downloadRef.baseType.c_str());
        if (downloadRef.baseType == "app")
        {
            // create current symbolic path
            fs::path completedIdPath = basePath / downloadRef.completedId;
            fs::path currentCompletedIdSymbolicPath = basePath / "app" / downloadRef.id / "current";

            std::string relativeCurrentPath = fs::relative(completedIdPath, currentCompletedIdSymbolicPath.parent_path()).string();
            kmlogger.info("relativeCurrentPath:  %s", relativeCurrentPath.c_str());

            fs::create_symlink(relativeCurrentPath, currentCompletedIdSymbolicPath);

            string appCommand = downloadRef.refApplication.command;
            kmlogger.info("appCommand:  %s", appCommand.c_str());

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

            // modify .desktop
            string desktopFileName = downloadRef.id + ".desktop";
            fs::path exportDesktopFilePath = commitDataPath / "export" / "share" / "applications" / desktopFileName;
            modifyDesktopFile(downloadRef, exportDesktopFilePath.string());

            // Create binData file: export/bin/ref.id
            fs::path binData = commitDataPath / "export" / "bin";
            kmlogger.info("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());
            }
            else
            {
                kmlogger.info("Directory already exists or creation failed.");
            }

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

            // deploy data: move "app/ref.id/current/active/export/" to "/var/opt/kaiming/"
            // fs::path exportsPath = basePath / "exports"; // For immutable system, we sheild this
            fs::path exportsPath = d->m_folder->getVarExportsPath();
            fs::path appExportPath = commitDataPath / "export";

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

            // 递归遍历源目录export/并处理文件
            modifyExportsDirectory(downloadRef, appExportPath.string(), exportsPath.string());
            kmlogger.info("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 metadataPath = commitDataPath / "metadata";
        GFile *metadataGFile = NULL; // /opt/kaiming/app/org.kde.kclock/current/active/metadata
        char *metadata_contents = NULL;
        GKeyFile *metadataFile = NULL;
        GVariant *commitDataGVariant = NULL;
        GVariant *commitMetadataGVariant = NULL;
        GCancellable *cancellable;
        GError **error;

        GBytes *deployData = NULL;
        GFile *deployDataGFile = NULL; // /opt/kaiming/app/org.kde.kclock/current/active/deploy
        fs::path deployDataFile = commitDataPath / "deploy";

        createFileIfNotExist(deployDataFile.string());

        metadataFile = g_key_file_new();
        if (!g_key_file_load_from_file(metadataFile, metadataPath.string().c_str(), G_KEY_FILE_NONE, NULL))
        {
            kmlogger.error("Failed to load the metadataFile.");
            return KM_ERROR_LOAD_METADATA_FILE_FAILED;
        }

        deployDataGFile = g_file_new_for_path(deployDataFile.string().c_str());
        kmlogger.info("deployDataFile: %s", deployDataFile.string().c_str());

        // metadataFile = downloadRef.resolvedMetakey;
        // if (metadataFile != NULL)
        //     printKeyfile(metadataFile);

        commitDataGVariant = ostreeManager.getCommitData(downloadRef.commit);
        if (!commitDataGVariant)
        {
            // 当 repo/config 和自己配置的REPO_URL不一致存在段错误
            kmlogger.error("get commit metadata error!");
            return KM_ERROR_GET_COMMIT_DATA_FAILED;
        }
        commitMetadataGVariant = g_variant_get_child_value(commitDataGVariant, 0);

        deployData = d->m_parseDeploy->deployDataToGBytes(downloadRef, commitDataPath, commitDataGVariant, commitMetadataGVariant, metadataFile);

        if (!d->m_parseDeploy->saveBytesToFile(deployDataGFile, deployData, cancellable, error))
        {
            return KM_ERROR_DEPLOY_DATA_FAILED;
        }

        // 创建 deploy ref
        ostreeManager.updateDeployRef(downloadRef.completedId, downloadRef.commit);

        g_key_file_free(metadataFile);
    }
    kmlogger.info("部署成功");

    return KM_ERROR_NO;
}

/**
 * @brief 组装完整的ref
 *
 * @param id 扩展、运行时或应用 id
 * @param arch 架构
 * @param branch 分支名，如master，或从subsummary 获取的 versions 关键字的分支
 * @return string 返回完整的ref
 */
string KMRepair::makeCompletedRef(string id, string arch, string branch)
{
    string completedRef = std::string("runtime/").append(id).append("/").append(arch).append("/").append(branch);
    return completedRef;
}

/**
 * @brief 根据ref获取运行时
 *
 * @param ref
 * @return std::string
 */
std::string KMRepair::getRuntimeFromRef(KMCommonRef &ref)
{
    string runtimePref;
    if (ref.baseType == "runtime")
    {
        // 运行时 "runtime"
        runtimePref = getValueByGroupAndKeyFromKVData(ref.metadata, "Runtime", "runtime"); // top.openkylin.Platform/x86_64/0.5
        runtimePref = std::string("runtime/").append(runtimePref);
        kmlogger.info("appref:  %s group [Application] runtime: %s", ref.completedId.c_str(), runtimePref.c_str());
    }
    else
    {
        // 应用 app
        runtimePref = getValueByGroupAndKeyFromKVData(ref.metadata, "Application", "runtime"); // app/org.kde.kclock/x86_64/master
        runtimePref = std::string("runtime/").append(runtimePref);
        kmlogger.info("appref:  %s group [Application] runtime: %s", ref.completedId.c_str(), runtimePref.c_str());
    }

    return runtimePref;
}

/**
 * @brief 根据ref获取基本类型
 *
 * @param ref
 * @return std::string
 */
std::string KMRepair::getBaseTypeFromRef(KMCommonRef &ref)
{

    if (KMUtil::startsWithForRef(ref.completedId, "app/"))
    {
        return "app";
    }
    else
    {
        return "runtime";
    }
}

/**
 * @brief 根据ref获取基本类型
 *
 * @param ref
 * @return std::string
 */
std::string KMRepair::getBaseTypeFromRef(string ref)
{
    if (KMUtil::startsWithForRef(ref, "app/"))
    {
        return "app";
    }
    else
    {
        return "runtime";
    }
}

/**
 * @brief 获取需要修复的 ref.id
 *
 * @return std::string
 */
std::string KMRepair::getDefaultId()
{
    return globalLastId;
}

/**
 * @brief 根据ref获取默认分支版本
 *
 * @param ref
 * @return std::string
 */
std::string KMRepair::getDefaultAppVersionRef(KMCommonRef &ref)
{
    string defaultAppBranch = KMUtil::getLastPartWithDelimiter(ref.completedId);
    kmlogger.info("default App branch::  %s", defaultAppBranch.c_str());
    return defaultAppBranch;
}

/**
 * @brief 根据ref获取默认分支版本
 *
 * @param ref
 * @return std::string
 */
std::string KMRepair::getDefaultRuntimeVersionRef(KMCommonRef &ref)
{
    string defaultRuntimeBranch = KMUtil::getLastPartWithDelimiter(ref.runtime);
    kmlogger.info("default runtime branch:  %s", defaultRuntimeBranch.c_str());
    return defaultRuntimeBranch;
}

/**
 * @brief 判断当前ref是否修复
 *
 * @param ref
 * @return true
 * @return false
 */
bool KMRepair::currentRefIsInstalled(KMCommonRef &ref)
{
    KMCommonRef installRef = makeRefDataFromInitRefString(ref.completedId);
    ref.baseType = getBaseTypeFromRef(ref.completedId);
    ref.id = installRef.id;
    ref.arch = installRef.arch;
    ref.branch = installRef.branch;

    KMRef appRef;
    appRef.kind = getBaseTypeFromRef(ref.completedId);
    appRef.id = installRef.id;
    appRef.arch = installRef.arch;
    appRef.branch = installRef.branch;
    appRef.refCommitId = ref.commit;
    // d->m_folder->setActive(appRef, ref.commit); // 避免 [error]: filesystem error: status: 符号连接的层数过多 [/opt/kaiming/app/org.kde.kclock/x86_64/master/active]

    kmlogger.info("adjust appRef weather is installed =>  kind:%s id:%s arch:%s branch:%s commit:%s", appRef.kind.c_str(), appRef.id.c_str(), appRef.arch.c_str(), appRef.branch.c_str(), appRef.refCommitId.c_str());

    if (d->m_folder->isInstalled(appRef))
    {
        return true;
    }

    return false;
}

const char **KMRepair::getGLDrivers()
{
    static gsize drivers = 0;

    if (g_once_init_enter(&drivers))
    {
        gsize newDrivers;
        char **newDriversChar = 0;
        const char *env = g_getenv("KAIMING_GL_DRIVERS");
        if (env != NULL && *env != 0)
        {
            newDriversChar = g_strsplit(env, ":", -1);
        }
        else
        {
            g_autofree char *nvidiaVersion = NULL;
            char *dot;
            GPtrArray *array = g_ptr_array_new();

            if (g_file_get_contents("/sys/module/nvidia/version", &nvidiaVersion, NULL, NULL))
            {
                g_strstrip(nvidiaVersion);
                /* Convert dots to dashes */
                while ((dot = strchr(nvidiaVersion, '.')) != NULL)
                {
                    *dot = '-';
                }
                g_ptr_array_add(array, g_strconcat("nvidia-", nvidiaVersion, NULL));
            }

            g_ptr_array_add(array, (char *)"default");
            g_ptr_array_add(array, (char *)"host");

            g_ptr_array_add(array, NULL);
            newDriversChar = (char **)g_ptr_array_free(array, false);
        }

        newDrivers = (gsize)newDriversChar;
        g_once_init_leave(&drivers, newDrivers);
    }

    return (const char **)drivers;
}

bool KMRepair::getHaveIntelGPU()
{
    static int haveIntelModule = -1;

    if (haveIntelModule == -1)
    {
        haveIntelModule = g_file_test("/sys/module/i915", G_FILE_TEST_EXISTS);
    }

    return haveIntelModule;
}

GHashTable *KMRepair::loadKernelModuleList()
{
    GHashTable *modules = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
    g_autofree char *modulesData = NULL;
    g_autoptr(GError) error = NULL;
    char *start, *end;

    if (!g_file_get_contents("/proc/modules", &modulesData, NULL, &error))
    {
        g_debug("Failed to read /proc/modules: %s", error->message);
        return modules;
    }

    /* /proc/modules is a table of modules.
     * Columns are split by spaces and rows by newlines.
     * The first column is the name. */
    start = modulesData;
    while (true)
    {
        end = strchr(start, ' ');
        if (end == NULL)
        {
            break;
        }

        g_hash_table_add(modules, g_strndup(start, (end - start)));

        start = strchr(end, '\n');
        if (start == NULL)
        {
            break;
        }

        start++;
    }

    return modules;
}

bool KMRepair::getHaveKernelModule(const char *moduleName)
{
    static GHashTable *kernelModules = NULL;

    if (g_once_init_enter(&kernelModules))
    {
        g_once_init_leave(&kernelModules, loadKernelModuleList());
    }

    return g_hash_table_contains(kernelModules, moduleName);
}

const char *KMRepair::getGtkTheme()
{
    static char *gtkTheme;

    if (g_once_init_enter(&gtkTheme))
    {
        /* The schema may not be installed so check first */
        GSettingsSchemaSource *source = g_settings_schema_source_get_default();
        g_autoptr(GSettingsSchema) schema = NULL;

        if (source == NULL)
        {
            g_once_init_leave(&gtkTheme, g_strdup(""));
        }
        else
        {
            schema = g_settings_schema_source_lookup(source, "org.gnome.desktop.interface", true);

            if (schema == NULL)
            {
                g_once_init_leave(&gtkTheme, g_strdup(""));
            }
            else
            {
                /* GSettings is used to store the theme if you use Wayland or GNOME.
                 * TODO: Check XSettings Net/ThemeName for other desktops.
                 * We don't care about any other method (like settings.ini) because they
                 *   aren't passed through the sandbox anyway. */
                g_autoptr(GSettings) settings = g_settings_new("org.gnome.desktop.interface");
                g_once_init_leave(&gtkTheme, g_settings_get_string(settings, "gtk-theme"));
            }
        }
    }

    return (const char *)gtkTheme;
}

/**
 * @brief 根据获取的metadata信息来判断当前ref是否需要下载
 *
 * @param metadata 从summary中根据ref获取的metadata信息
 * @return true  需要下载
 * @return false 不需要下载
 */
bool KMRepair::needDownloadByMetadata(const char *metadata)
{
    GBytes *metadataBytes = NULL;
    metadataBytes = g_bytes_new(metadata, strlen(metadata));
    bool needDownload = false;

    kmlogger.info("need download by metadata: %s", metadata);
    GKeyFile *metakey = g_key_file_new();
    if (!g_key_file_load_from_bytes(metakey, metadataBytes, G_KEY_FILE_NONE, NULL))
    {
        kmlogger.info("get resolvedMetadata, resolvedMetakey from metadata ");
        return false;
    }

    g_auto(GStrv) groups = NULL;
    groups = g_key_file_get_groups(metakey, NULL);
    for (int i = 0; groups[i] != NULL; i++)
    {
        char *taggedExtension;
        if (g_str_has_prefix(groups[i], "Extension ") && *(taggedExtension = (groups[i] + strlen("Extension "))) != 0)
        {
            kmlogger.info("search groups: %s ", groups[i]);

            char *extension = NULL;
            char *version = g_key_file_get_string(metakey, groups[i], "version", NULL);
            g_auto(GStrv) versions = g_key_file_get_string_list(metakey, groups[i], "versions", NULL, NULL);
            bool subdirectories = g_key_file_get_boolean(metakey, groups[i], "subdirectories", NULL);
            bool noAutodownload = false;
            noAutodownload = g_key_file_get_boolean(metakey, groups[i], "no-autodownload", NULL);
            char *downloadIf = g_key_file_get_string(metakey, groups[i], "download-if", NULL);
            char *autopruneUnless = g_key_file_get_string(metakey, groups[i], "autoprune-unless", NULL);
            bool autodelete = g_key_file_get_boolean(metakey, groups[i], "autodelete", NULL);
            bool localeSubset = false;
            localeSubset = g_key_file_get_boolean(metakey, groups[i], "locale-subset", NULL);

            /* Parse actual extension name */
            parseExtensionWithTag(taggedExtension, &extension, NULL);
            kmlogger.info("extension:  %s", extension);

            kmlogger.info("extension: %s  downloadIf:%s noAutodownload: %d", extension, downloadIf, noAutodownload);

            needDownload = matchExtensionRules(extension, downloadIf, noAutodownload);
        }
    }
    return needDownload;
}

/**
 * @brief 匹配扩展 id 是否需要下载
 *
 * @param extensionId 扩展id
 * @param reasons 何时需要下载,由 "download-if" 指定
 * @param defaultValue 默认需要下载值,由 "no-autodownload" 指定
 * @return true 需要下载
 * @return false 不需要下载
 */
bool KMRepair::matchExtensionRules(const char *extensionId, const char *reasons, bool defaultValue)
{
    const char *extensionBasename;
    g_auto(GStrv) reasonList = NULL;
    size_t i;

    if (reasons == NULL || *reasons == 0)
    {
        return defaultValue;
    }

    extensionBasename = strrchr(extensionId, '.');
    if (extensionBasename == NULL)
    {
        return false;
    }
    extensionBasename += 1;
    kmlogger.info("extensionBasename: %s", extensionBasename);

    reasonList = g_strsplit(reasons, ";", -1);

    for (i = 0; reasonList[i]; ++i)
    {
        const char *reason = reasonList[i];

        if (strcmp(reason, "active-gl-driver") == 0)
        {
            /* handled below */
            const char **glDrivers = getGLDrivers();
            size_t j;

            for (j = 0; glDrivers[j]; j++)
            {
                kmlogger.info("glDrivers: %s", glDrivers[j]);
                if (strcmp(glDrivers[j], extensionBasename) == 0)
                {
                    return true;
                }
            }
        }
        else if (strcmp(reason, "active-gtk-theme") == 0)
        {
            const char *gtkTheme = getGtkTheme();
            kmlogger.info("gtkTheme: %s", gtkTheme);
            if (strcmp(gtkTheme, extensionBasename) == 0)
            {
                return true;
            }
        }
        else if (strcmp(reason, "have-intel-gpu") == 0)
        {
            /* Used for Intel VAAPI driver extension */
            if (getHaveIntelGPU())
            {
                return true;
            }
        }
        else if (g_str_has_prefix(reason, "have-kernel-module-"))
        {
            const char *moduleName = reason + strlen("have-kernel-module-");

            if (getHaveKernelModule(moduleName))
            {
                return true;
            }
        }
        else if (g_str_has_prefix(reason, "on-xdg-desktop-"))
        {
            const char *desktopName = reason + strlen("on-xdg-desktop-");
            const char *currentDesktopVar = g_getenv("XDG_CURRENT_DESKTOP");
            g_auto(GStrv) currentDesktopNames = NULL;
            size_t j;

            if (!currentDesktopVar)
            {
                continue;
            }

            currentDesktopNames = g_strsplit(currentDesktopVar, ":", -1);

            for (j = 0; currentDesktopNames[j]; ++j)
            {
                if (g_ascii_strcasecmp(desktopName, currentDesktopNames[j]) == 0)
                {
                    return true;
                }
            }
        }
    }

    return false;
}

void KMRepair::init()
{
    d->m_options = make_shared<Options>();
    d->m_folder = shared_ptr<KMFolder>(new KMFolder("/opt/kaiming", false));
    d->ostree_handler = shared_ptr<KMOSTreeHandler>(new KMOSTreeHandler(d->m_folder->getRepoPath()));
    d->map_refs = d->ostree_handler->getLocalRefs(REPO_NAME);
    d->m_remoteSummary = shared_ptr<KMRemoteSummary>(new KMRemoteSummary());
    d->m_util = shared_ptr<KMUtil>(new KMUtil());
    d->m_env = shared_ptr<KMEnv>(new KMEnv());
    d->m_parseDeploy = shared_ptr<KMParseDeploy>(new KMParseDeploy());
}

/**
 * @brief 测试调用的api
 *
 * @param name 开明包名，如org.kde.kclock
 * @param version 开明版本号，这里实际上是ostree branch版本，暂未细化到具体子版本。空代表最新版本，如"master"
 * @return true
 * @return false
 */
bool KMRepair::testInstall(string name, string version)
{
    int ret = false;
    vector<string> vecInstall;

    d->m_appRef = makeRefDataFromInitRefString(name);
    vecInstall.push_back(name);

    ret = start(vecInstall);

    return ret;
}

/**
 * @brief 给软件商店调用的api
 *
 * @param name 开明包名，如org.kde.kclock
 * @param version 开明版本号，这里实际上是ostree branch版本，暂未细化到具体子版本。空代表最新版本，如"master"
 * @param installCallback 进度回调函数
 * @param error
 * @return true
 * @return false
 */
int KMRepair::install(string name, string version, int &error, InstallCallBack installCallback)
{
    kmlogger.info("begin install");
    globalProgressCallback = installCallback;

    int ret = KM_ERROR_NOTHING_TO_DO;
    vector<string> vecInstall;

    d->m_appRef = makeRefDataFromInitRefString(name);
    vecInstall.push_back(name);

    init();

    ret = start(vecInstall);

    error = ret;

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

int KMRepair::repair(string name)
{
    kmlogger.info("begin repair");

    int ret = KM_ERROR_NOTHING_TO_DO;
    vector<string> vecInstall;

    d->m_appRef = makeRefDataFromInitRefString(name);
    vecInstall.push_back(name);

    init();

    ret = uninstall(name);
    if (ret != KM_ERROR_NO)
    {
        return KM_ERROR_UNINSTALL_FAILED;
    }

    ret = start(vecInstall);

    kmlogger.info("end repair");
    return ret;
}

int KMRepair::uninstall(string name)
{
    if (!d->m_folder->isInstalled(name))
    {
        kmlogger.info("%s not installed!", name.c_str());
        return KM_ERROR_NOT_INSTALLED;
    }
    kmlogger.info("find installed package %s", name.c_str());

    // 从本地 repo 中删除,先删除repo对象数据比较合理
    for (auto pair : d->map_refs)
    {
        if (pair.second.id == name)
        {
            string refString = pair.second.kind + "/" + pair.second.id + "/" + pair.second.arch + "/" + pair.second.branch;

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

            if (!d->ostree_handler->deleteRefTag(REPO_NAME, refString))
            {
                return KM_ERROR_DELETE_REF_TAG_FAILED;
            }

            if (!d->ostree_handler->repoPrune())
            {
                return KM_ERROR_PRUNE_REPO_FAILED;
            }
        }
    }

    // 通过元数据文件解析需要删除的包
    unique_ptr<KMMetaData> metadata;
    if (d->m_folder->isApp(name))
    {
        metadata = unique_ptr<KMMetaData>(new KMMetaData());
        // 遍历

        if (metadata->load(d->m_folder->getActivePath(name) / "metadata"))
        {
            // 重新更新 export
            // 首先处理软链接，全部删除相关的软链接
            for (auto const &dirEntry : fs::recursive_directory_iterator(d->m_folder->getExportsPath()))
            {
                if (fs::is_symlink(dirEntry) && (int)fs::read_symlink(dirEntry).string().find(name) > 0)
                {
                    kmlogger.info("remove %s", dirEntry.path().c_str());
                    if (!fs::remove_all(dirEntry))
                    {
                        kmlogger.error("uninstall %s error, can\'t delete exports file.", name.c_str());
                        return KM_ERROR_DELETE_EXPORT_FILES_FAILED;
                    }
                }
            }
        }

        // 删除 app 数据文件夹，当使用system dbus 用户是root启动,不存在 $HOME,为了避免string(nullptr)导致的段错误让服务执行失败，因此先注释
        kmlogger.info("remove package %s data dir", name.c_str());

        // 删除文件夹
        kmlogger.info("remove app %s install dir", name.c_str());
        if (fs::exists(d->m_folder->getAppPath() / name))
        {
            if (!fs::remove_all(d->m_folder->getAppPath() / name))
            {
                kmlogger.error("uninstall %s error, can\'t delete the directory.", name);
                return KM_ERROR_DELETE_DIRECTORY_FAILED;
            }
        }
    }
    else if (d->m_folder->isRuntime(name))
    {
        metadata = unique_ptr<KMMetaData>(new KMMetaData(false));
        // 卸载运行时要考虑有没有应用依赖此运行时

        for (auto pair : d->map_refs)
        {
            if (pair.second.id == name)
            {
                metadata->load(d->m_folder->getRuntimePath() / name / pair.second.arch / pair.second.branch / "active" / "metadata");
                break;
            }
        }
        // 删除文件夹
        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 KM_ERROR_DELETE_DIRECTORY_FAILED;
        }
    }

    // 删除扩展
    for (auto ext : metadata->getExtensions())
    {
        kmlogger.info("remove extension %s", ext.name.c_str());
        if (ext.autodelete && d->m_folder->isInstalled(ext.name))
        {
            int ret = uninstall(ext.name);
            if (ret != KM_ERROR_NO)
            {
                return ret;
            }
        }
    }

    return KM_ERROR_NO;
}

/**
 * @brief 当前包是否修复
 *
 * @param name
 * @return int
 */
int KMRepair::isInstalled(string name)
{
    kmlogger.info("Check wait for installing app %s", name.c_str());
    KMCommonRef appCommonRef;
    appCommonRef.pref = name;
    appCommonRef = makeRefDataFromInitRefString(appCommonRef.pref);

    KMRef appRef;
    appRef.kind = getBaseTypeFromRef(appCommonRef.completedId);
    kmlogger.info("kind: %s", appRef.kind.c_str());
    appRef.id = appCommonRef.id;
    kmlogger.info("id: %s", appRef.id.c_str());
    appRef.arch = appCommonRef.arch;
    kmlogger.info("arch: %s", appRef.arch.c_str());
    appRef.branch = appCommonRef.branch;
    kmlogger.info("branch: %s", appRef.branch.c_str());

    kmlogger.info("kind:%s id:%s arch:%s branch:%s", appRef.kind.c_str(), appRef.id.c_str(), appRef.arch.c_str(), appRef.branch.c_str());

    if (d->m_folder->isInstalled(appRef))
    {
        kmlogger.info("is installed");
        return KM_ERROR_NO;
    }

    return KM_ERROR_NOT_INSTALLED;
}

static const char *getFilePathCached(GFile *file)
{
    const char *path;
    static GQuark filePathQuark = 0;

    if (G_UNLIKELY(filePathQuark == 0))
    {
        filePathQuark = g_quark_from_static_string("kaiming-file-path");
    }

    do
    {
        path = (char *)g_object_get_qdata((GObject *)file, filePathQuark);
        if (path == NULL)
        {
            char *newFilePath = NULL;
            newFilePath = g_file_get_path(file);
            if (newFilePath == NULL)
            {
                return NULL;
            }

            if (g_object_replace_qdata((GObject *)file, filePathQuark, NULL, newFilePath, g_free, NULL))
            {
                path = KMUtil::stealPointer(&newFilePath);
            }
        }
    } while (path == NULL);

    return path;
}

/**
 * @brief 得到下载refs列表
 *
 * @param ref  待处理的ref
 * @param metadata
 * @return true
 * @return false
 */
bool KMRepair::getDownloadRefsList(KMCommonRef &ref, char *metadata)
{
    GBytes *metadataBytes = NULL;
    metadataBytes = g_bytes_new(metadata, strlen(metadata));

    kmlogger.info("get resolvedMetadata, resolvedMetakey from metadata ");
    GKeyFile *metakey = g_key_file_new();
    if (!g_key_file_load_from_bytes(metakey, metadataBytes, G_KEY_FILE_NONE, NULL))
    {
        kmlogger.info("get resolvedMetadata, resolvedMetakey from metadata ");
        return false;
    }
    ref.resolvedMetadata = g_bytes_ref(metadataBytes);
    ref.resolvedMetakey = KMUtil::stealPointer(&metakey);

    //  (const char *)g_bytes_get_data (metadataBytes)
    char *runtimeCompleteData = NULL;
    runtimeCompleteData = g_key_file_get_string(ref.resolvedMetakey, "Application", "runtime", NULL);
    kmlogger.info("%s is app, from group [Application] to find runtime: %s", ref.completedId.c_str(), runtimeCompleteData);

    g_auto(GStrv) groups = NULL;
    groups = g_key_file_get_groups(ref.resolvedMetakey, NULL);
    for (int i = 0; groups[i] != NULL; i++)
    {
        char *taggedExtension;
        if (g_str_has_prefix(groups[i], "Extension ") && *(taggedExtension = (groups[i] + strlen("Extension "))) != 0)
        {
            kmlogger.info("search groups: %s ", groups[i]);

            char *extension = NULL;
            char *version = g_key_file_get_string(ref.resolvedMetakey, groups[i], "version", NULL);
            g_auto(GStrv) versions = g_key_file_get_string_list(ref.resolvedMetakey, groups[i], "versions", NULL, NULL);
            bool subdirectories = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "subdirectories", NULL);
            bool noAutodownload = false;
            noAutodownload = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "no-autodownload", NULL);
            char *downloadIf = g_key_file_get_string(ref.resolvedMetakey, groups[i], "download-if", NULL);
            char *autopruneUnless = g_key_file_get_string(ref.resolvedMetakey, groups[i], "autoprune-unless", NULL);
            bool autodelete = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "autodelete", NULL);
            bool localeSubset = false;
            localeSubset = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "locale-subset", NULL);

            /* Parse actual extension name */
            parseExtensionWithTag(taggedExtension, &extension, NULL);
            kmlogger.info("extension:  %s", extension);

            const char *defaultBranches[] = { NULL, NULL };
            const char **branches;
            int branchInt;

            if (versions)
            {
                branches = (const char **)versions;
            }
            else
            {
                if (version)
                {
                    kmlogger.info("version branch:  %s", version);
                    defaultBranches[0] = version;
                }
                else
                {
                    // 跟随runtime运行时的版本
                    defaultBranches[0] = ref.defaultRuntimeBranch.c_str();
                    kmlogger.info("default branch:  %s", defaultBranches[0]);
                }
                branches = defaultBranches;
            }

            // 对每个分支逐个遍历
            for (branchInt = 0; branches[branchInt] != NULL; branchInt++)
            {
                char *checksum = NULL;
                const char *branch = branches[branchInt];
                kmlogger.info("extension: %s branch: %s downloadIf:%s noAutodownload: %d", extension, branch, downloadIf, noAutodownload);

                bool noNeedDownload = matchExtensionRules(extension, downloadIf, noAutodownload);
                if (noNeedDownload)
                {
                    kmlogger.info("extension: %s don't need download!", extension);
                    continue;
                }

                string completeRef = makeCompletedRef(string(extension), d->m_appRef.arch, string(branch));
                kmlogger.info("completedRef:  %s", completeRef.c_str());

                // completeRef = "runtime/org.freedesktop.Platform.GL.default/x86_64/22.08";
                char *runtimeChecksum = NULL;
                VarRefInfoRef info;
                if (d->m_remoteSummary->summaryLookupRefCommitAndInfo(d->m_appRef.subsummary, NULL, completeRef.c_str(), &runtimeChecksum, &info))
                {
                    kmlogger.info("add_related=> runtime ref:%s commitid: %s", completeRef.c_str(), runtimeChecksum);

                    KMCommonRef installRef;
                    installRef.remote = REPO_NAME;
                    installRef.info = info;
                    installRef.subsummary = d->m_appRef.subsummary;
                    installRef.completedId = completeRef;
                    installRef.commit = string(runtimeChecksum);

                    kmlogger.info("runtime ref info=> id:  %s commit: %s", installRef.completedId.c_str(), installRef.commit.c_str());

                    const char *metadata = NULL;

                    if (!d->m_remoteSummary->summaryRemoteStateLookupCache(installRef.subsummary, installRef.completedId.c_str(), &installRef.downloadSize, &installRef.installedSizeInt, &metadata))
                    {
                        // 获取当前 ref 的相关信息
                        kmlogger.error("Not get info from this ref  %s", installRef.completedId.c_str());
                        return false;
                    }

                    installRef.applicationInfo = string(metadata, metadata + strlen(metadata));

                    // kmlogger.debug("runtime ref id:   %s applicationInfo: %s", installRef.completedId.c_str(), installRef.applicationInfo.c_str());

                    // if (needDownloadByMetadata(metadata))
                    d->m_refDownloadList.push_back(installRef);
                }
                else if (subdirectories)
                {
                    vector<string> subrefRefs = d->m_remoteSummary->summaryMatchSubrefs(ref.subsummary, nullptr, completeRef.c_str(), extension, d->m_appRef.arch.c_str(), branch);
                    for (auto &subrefRef : subrefRefs)
                    {
                        kmlogger.info("completedRef:%s extension:%s subrefRef:%s", completeRef.c_str(), extension, subrefRef);
                    }

                    for (const std::string &subrefRef : subrefRefs)
                    {
                        // kmlogger.info("1 add_related=>  subdirectories subrefRef: %s",  subrefRef);
                        char *subrefChecksum = NULL;
                        VarRefInfoRef subrefInfo;
                        if (d->m_remoteSummary->summaryLookupRefCommitAndInfo(ref.subsummary, nullptr, subrefRef.c_str(), &subrefChecksum, &subrefInfo))
                        {
                            kmlogger.info("add_related=>  subdirectories subrefRef: %s checksum:%s ", subrefRef.c_str(), subrefChecksum);

                            KMCommonRef installSubRef;
                            installSubRef.remote = REPO_NAME;
                            installSubRef.subsummary = ref.subsummary;
                            installSubRef.completedId = subrefRef;
                            installSubRef.commit = string(subrefChecksum);
                            installSubRef.info = subrefInfo;

                            const char *metadata = NULL;

                            if (!d->m_remoteSummary->summaryRemoteStateLookupCache(installSubRef.subsummary, installSubRef.completedId.c_str(), &installSubRef.downloadSize, &installSubRef.installedSizeInt, &metadata))
                            {
                                // 获取当前 ref 的相关信息
                                kmlogger.error("Not get info from this ref  %s", installSubRef.completedId.c_str());
                                return false;
                            }

                            installSubRef.applicationInfo = string(metadata, metadata + strlen(metadata));

                            // kmlogger.debug("runtime ref id:   %s applicationInfo: %s", installSubRef.completedId.c_str(), installSubRef.applicationInfo.c_str());

                            // if (needDownloadByMetadata(metadata))
                            d->m_refDownloadList.push_back(installSubRef);
                        }
                    }
                }
            }
        }
    }

    return true;
}

void KMRepair::parseExtensionWithTag(const char *extension, char **name, char **tag)
{
    const char *tagExtensionChar = strchr(extension, '@');

    if (tagExtensionChar)
    {
        if (name != NULL)
        {
            *name = g_strndup(extension, tagExtensionChar - extension);
        }

        /* Everything after the @ */
        if (tag != NULL)
        {
            *tag = g_strdup(tagExtensionChar + 1);
        }

        return;
    }

    if (name != NULL)
    {
        *name = g_strdup(extension);
    }

    if (tag != NULL)
    {
        *tag = NULL;
    }
}

/**
 * @brief 创建一个 export/bin/ref.id shell脚本，写入执行内容，并赋予0755权限
 *
 * @param fileName
 * @param ref
 * @return true
 * @return false
 */
bool KMRepair::createExportBinShellScript(KMCommonRef ref, string fileName)
{
    // 设置内容
    string shellHead = "#!/bin/sh";
    string content = shellHead.append("\nexec ").append("/usr/bin/kaiming run --branch=").append(ref.branch).append(" --arch=").append(ref.arch).append(" ").append(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;
}

/**
 * @brief 检查文件是否存在，如果不存在则创建文件并输入空字符串
 *
 * demo:
 *       新建 "active/files/.ref"，并输入空字符串 ""
 *
 * @param filename
 */
void KMRepair::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();
}

/**
 * @brief 当文件不存在时，创建文件
 *
 * @param filename
 */
void KMRepair::createFileIfNotExist(const std::string &filename)
{
    fs::path filePath(filename);

    if (!fs::exists(filePath))
    {
        // 文件不存在，创建文件
        std::ofstream file(filename);
        if (file.good())
        {
            kmlogger.info("File created successfully.");
        }
        else
        {
            kmlogger.error("Failed to create file.");
        }
    }
    else
    {
        kmlogger.info("File already exists.");
    }
}

/**
 * @brief 读取 .desktop 文件内容
 *
 * @param filename
 * @return std::vector<std::string>
 */
std::vector<std::string> KMRepair::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;
}

/**
 * @brief 修改 .desktop 文件内容
 *
 * @param filename
 * @param newLines
 * @return true
 * @return false
 */
bool KMRepair::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;
    }
}

/**
 * @brief 读取 键值对文件(如.desktop, .service) 中具体字段的值
 *
 * @param lines
 * @param key
 * @return std::string
 */
std::string KMRepair::getValueByKeyFromKVData(const std::vector<std::string> &lines, string key)
{
    for (const auto &line : lines)
    {
        if (line.find(key) != std::string::npos)
        {
            return line.substr(key.size()); // 去掉 "Exec=" 的前缀，返回剩余的部分
        }
    }
    return ""; // 没有找到 key 字段，返回空字符串
}

void KMRepair::printKeyfile(GKeyFile *keyfile)
{
    if (keyfile == NULL)
        return;

    gsize length = 0;
    gchar **groups = g_key_file_get_groups(keyfile, &length);

    for (gsize i = 0; i < length; ++i)
    {
        kmlogger.info("Groups: [%s]", groups[i]);

        gsize keysLength = 0;
        gchar **keys = g_key_file_get_keys(keyfile, groups[i], &keysLength, NULL);

        for (gsize j = 0; j < keysLength; ++j)
        {
            gchar *value = g_key_file_get_string(keyfile, groups[i], keys[j], NULL);
            kmlogger.info("%s = %s", keys[j], value);
            g_free(value);
        }

        g_strfreev(keys);
    }

    g_strfreev(groups);
}

/**
 * @brief 接受组名和键值对的 key，然后从字符串中提取对应的值
 *
 * @param metadata 待搜索的字符串
 * @param groupName 组名
 * @param key 关键字key
 * @return std::string
 */
std::string KMRepair::getValueByGroupAndKeyFromKVData(const std::string &metadata, const std::string &groupName, const std::string &key)
{
    std::istringstream iss(metadata);
    std::string line;

    // 逐行读取 metadata
    while (std::getline(iss, line))
    {
        // 查找 [groupName] 开始的组
        size_t startPos = line.find(groupName);
        if (startPos != std::string::npos)
        {
            // 找到了组，继续读取键值对
            std::unordered_map<std::string, std::string> keyValuePairs;

            while (std::getline(iss, line) && !line.empty() && line[0] != '[')
            {
                size_t eqPos = line.find('=');
                if (eqPos != std::string::npos)
                {
                    std::string key = line.substr(0, eqPos);
                    std::string value = line.substr(eqPos + 1);
                    keyValuePairs[key] = value;
                }
            }

            // 在当前组中查找键值对的值
            if (!keyValuePairs.empty())
            {
                auto it = keyValuePairs.find(key);
                if (it != keyValuePairs.end())
                {
                    return it->second;
                }
            }
        }
    }

    return ""; // 未找到对应值
}

/**
 * @brief 获取当前目录下的所有文件
 *
 * 对于获取service文件有用
 *
 * @param directoryPath
 * @param files
 * @return true
 * @return false
 */
bool KMRepair::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; // 获取文件列表失败
    }
}

/**
 * @brief 更改service文件
 *
 * @param ref
 * @param serviceFileDirectoryPath
 */
void KMRepair::modifyServiceFile(KMCommonRef &ref, 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.info("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(ref.branch).append(" ").append("--arch=").append(ref.arch).append(" ").append("--command=").append(value).append(" ").append(ref.id);
                        line = content;
                    }
                }

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

/**
 * @brief 更改desktop文件，比如修改Exec, Icon, X-Kaiming
 *
 * @param ref
 * @param exportDesktopFilePath
 */
void KMRepair::modifyDesktopFile(KMCommonRef &ref, 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, ref.id);
            kmlogger.info("formatExec: %s", formatExec.c_str());

            string serviceExec = "Exec=";
            string content = serviceExec.append("/usr/bin/kaiming run ").append("--branch=").append(ref.branch).append(" ").append("--arch=").append(ref.arch).append(" ").append("--command=").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=" + ref.id;
        desktopDatas.push_back(kaimingTag);
    }

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

/**
 * @brief 递归遍历exports/目录并处理文件，比如创建软链接
 *
 * @param ref
 * @param srcDir
 * @param destDir
 */
void KMRepair::modifyExportsDirectory(KMCommonRef &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.info("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());

                fs::create_symlink(fs::path(relativePath), fs::path(destFilePath));
            }
            else if (srcFilePath.find("export/bin") != std::string::npos)
            {
                // 如果是 export/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::create_symlink(fs::path(relativePath), fs::path(destFilePath));
            }
        }
    }
}

/**
 * @brief 接受不定数量的 cacheShellPath 参数，并将它们拼接到命令中，然后执行命令
 *
 * 作用是生成应用desktop, icon, service等缓存
 *
 * @param cacheShellPaths
 */
void KMRepair::runMultiperTriggerUpdateCacheCommand(const vector<string> &cacheShellPaths)
{
    for (const auto &path : cacheShellPaths)
    {
        runTriggerUpdateCacheCommand(path);
    }
}

/**
 * @brief 接受不定数量的 cacheShellPath 参数，并将它们拼接到命令中，然后执行命令
 *
 *
 * @param cacheShellPaths
 */
void KMRepair::runTriggerUpdateCacheCommand(const std::string &cacheShellPath)
{
    // 使用 std::ostringstream 拼接命令
    std::ostringstream commandStream;
    commandStream << KMUtil::getKMBox() << " --unshare-ipc --unshare-net --unshare-pid --ro-bind / / --proc /proc --dev /dev --bind "
                  << " /opt/kaiming /opt/kaiming " << cacheShellPath << " /opt/kaiming";

    std::string command = commandStream.str();

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

/**
 * @brief  判断当前类型是否为整形类型
 *
 * @param str
 * @return true
 * @return false
 */
bool KMRepair::isInteger(const std::string &str)
{
    try
    {
        // 尝试将字符串转换为整数
        int num = std::stoi(str);
        // 没有抛出异常，则转换成功，返回 true
        return true;
    }
    catch (const std::invalid_argument &)
    {
        // 抛出 std::invalid_argument 异常，表示字符串不是一个有效的整数
        return false;
    }
    catch (const std::out_of_range &)
    {
        // 抛出 std::out_of_range 异常，表示转换后的整数超出了可表示的范围
        return false;
    }
}

/**
 * @brief 格式化输出下载的包信息，运行时输出是下载大小，软件包是修复大小
 *
 * @param ref
 * @param index
 */
void KMRepair::printRefInfo(KMCommonRef &ref, int index)
{
    string installedSize;
    if (ref.baseType == "app")
    {
        installedSize = formatFileSize((double)ref.installedSizeInt);
    }
    else
    {
        installedSize = formatFileSize((double)ref.downloadSize);
    }

    ref.installedSize = installedSize;

    printf("%-5s %-50s %-20s %-10s %-20s %-20s\n", std::to_string(index).c_str(), ref.id.c_str(), ref.branch.c_str(), "i", ref.remote.c_str(), installedSize.c_str());
}

/**
 * @brief 格式化文件大小
 *
 * @param size
 * @return string
 */
string KMRepair::formatFileSize(double size)
{
    vector<string> units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
    int index = 0;

    while (size >= 1024.0 && index < units.size())
    {
        size /= 1024.0;
        index++;
    }

    std::ostringstream oss;
    oss << std::fixed << std::setprecision(1) << size << " " << units[index];
    return oss.str();
}

/**
 * @brief 得到离线refs列表
 *
 * @param ref  待处理的ref
 * @param metadata
 * @return true
 * @return false
 */
bool KMRepair::getSideloadRefsList(KMCommonRef &ref, char *metadata, const string &collectionId)
{
    GBytes *metadataBytes = NULL;
    metadataBytes = g_bytes_new(metadata, strlen(metadata));

    kmlogger.info("get resolvedMetadata, resolvedMetakey from metadata ");
    GKeyFile *metakey = g_key_file_new();
    if (!g_key_file_load_from_bytes(metakey, metadataBytes, G_KEY_FILE_NONE, NULL))
    {
        kmlogger.info("get resolvedMetadata, resolvedMetakey from metadata ");
        return false;
    }
    ref.resolvedMetadata = g_bytes_ref(metadataBytes);
    ref.resolvedMetakey = KMUtil::stealPointer(&metakey);

    //  (const char *)g_bytes_get_data (metadataBytes)
    char *runtimeCompleteData = NULL;
    runtimeCompleteData = g_key_file_get_string(ref.resolvedMetakey, "Application", "runtime", NULL);
    kmlogger.info("%s is app, from group [Application] to find runtime: %s", ref.completedId.c_str(), runtimeCompleteData);

    g_auto(GStrv) groups = NULL;
    groups = g_key_file_get_groups(ref.resolvedMetakey, NULL);
    for (int i = 0; groups[i] != NULL; i++)
    {
        char *taggedExtension;
        if (g_str_has_prefix(groups[i], "Extension ") && *(taggedExtension = (groups[i] + strlen("Extension "))) != 0)
        {
            kmlogger.info("search groups: %s ", groups[i]);

            char *extension = NULL;
            char *version = g_key_file_get_string(ref.resolvedMetakey, groups[i], "version", NULL);
            g_auto(GStrv) versions = g_key_file_get_string_list(ref.resolvedMetakey, groups[i], "versions", NULL, NULL);
            bool subdirectories = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "subdirectories", NULL);
            bool noAutodownload = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "no-autodownload", NULL);
            char *downloadIf = g_key_file_get_string(ref.resolvedMetakey, groups[i], "download-if", NULL);
            char *autopruneUnless = g_key_file_get_string(ref.resolvedMetakey, groups[i], "autoprune-unless", NULL);
            bool autodelete = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "autodelete", NULL);
            bool localeSubset = g_key_file_get_boolean(ref.resolvedMetakey, groups[i], "locale-subset", NULL);

            /* Parse actual extension name */
            parseExtensionWithTag(taggedExtension, &extension, NULL);
            kmlogger.info("extension:  %s", extension);

            const char *defaultBranches[] = { NULL, NULL };
            const char **branches;
            int branchInt;

            if (versions)
            {
                branches = (const char **)versions;
            }
            else
            {
                if (version)
                {
                    kmlogger.info("version branch:  %s", version);
                    defaultBranches[0] = version;
                }
                else
                {
                    // 跟随runtime运行时的版本
                    defaultBranches[0] = ref.defaultRuntimeBranch.c_str();
                    kmlogger.info("default branch:  %s", defaultBranches[0]);
                }
                branches = defaultBranches;
            }

            vector<string> vecFindRef;
            for (branchInt = 0; branches[branchInt] != NULL; branchInt++)
            {
                char *checksum = NULL;
                const char *branch = branches[branchInt];
                kmlogger.info("extension: %s branch: %s", extension, branch);

                string completeRef = makeCompletedRef(string(extension), d->m_appRef.arch, string(branch));
                kmlogger.info("completedRef:  %s", completeRef.c_str());

                // completeRef = "runtime/org.freedesktop.Platform.GL.default/x86_64/22.08";
                char *runtimeChecksum = NULL;
                VarRefInfoRef info;
                if (d->m_remoteSummary->sideloadSummaryLookupRefCommitAndInfo(d->m_appRef.subsummary, collectionId.c_str(), vecFindRef, completeRef, &runtimeChecksum, &info))
                {
                    vecFindRef.emplace_back(completeRef);
                    kmlogger.info("add_related=> runtime ref:%s commitid: %s", completeRef.c_str(), runtimeChecksum);

                    KMCommonRef installRef;
                    installRef.remote = REPO_NAME;
                    installRef.info = info;
                    installRef.subsummary = d->m_appRef.subsummary;
                    installRef.completedId = completeRef;
                    installRef.commit = string(runtimeChecksum);

                    kmlogger.info("runtime ref info=> id:  %s commit: %s", installRef.completedId.c_str(), installRef.commit.c_str());

                    const char *metadata = NULL;
                    KMOSTreeHandler sideOstreeManager(d->m_options->m_sideload);
                    g_autoptr(GVariant) pCommitdata = sideOstreeManager.getCommitData(installRef.commit);
                    if (!d->m_remoteSummary->summarySideloadRemoteState(pCommitdata, &installRef.downloadSize, &installRef.installedSizeInt, &metadata))
                    {
                        kmlogger.error("Not get info from this ref: %s", ref);
                        return KM_ERROR_GET_REF_INFO_FAILED;
                    }

                    installRef.applicationInfo = string(metadata, metadata + strlen(metadata));

                    kmlogger.debug("runtime ref id:   %s applicationInfo: %s", installRef.completedId.c_str(), installRef.applicationInfo.c_str());

                    d->m_refDownloadList.push_back(installRef);
                }
                else if (subdirectories)
                {
                    vector<string> subrefRefs = d->m_remoteSummary->summaryMatchSubrefs(ref.subsummary, collectionId.c_str(), completeRef.c_str(), extension, d->m_appRef.arch.c_str(), branch);

                    for (std::string subrefRef : subrefRefs)
                    {
                        // kmlogger.info("1 add_related=>  subdirectories subrefRef: %s",  subrefRef);
                        char *subrefChecksum = NULL;
                        VarRefInfoRef subrefInfo;
                        if (d->m_remoteSummary->sideloadSummaryLookupRefCommitAndInfo(ref.subsummary, collectionId.c_str(), vecFindRef, subrefRef, &subrefChecksum, &subrefInfo))
                        {
                            kmlogger.info("add_related=>  subdirectories subrefRef: %s checksum:%s ", subrefRef.c_str(), subrefChecksum);
                            vecFindRef.emplace_back(subrefRef);
                            KMCommonRef installSubRef;
                            installSubRef.remote = REPO_NAME;
                            installSubRef.subsummary = ref.subsummary;
                            installSubRef.completedId = subrefRef;
                            installSubRef.commit = string(subrefChecksum);
                            installSubRef.info = subrefInfo;

                            const char *metadata = NULL;
                            KMOSTreeHandler sideOstreeManager(d->m_options->m_sideload);
                            g_autoptr(GVariant) pCommitdata = sideOstreeManager.getCommitData(installSubRef.commit);
                            if (!d->m_remoteSummary->summarySideloadRemoteState(pCommitdata, &installSubRef.downloadSize, &installSubRef.installedSizeInt, &metadata))
                            {
                                kmlogger.error("Not get info from this ref: %s", ref);
                                return KM_ERROR_GET_REF_INFO_FAILED;
                            }

                            installSubRef.applicationInfo = string(metadata, metadata + strlen(metadata));

                            kmlogger.debug("runtime ref id:   %s applicationInfo: %s", installSubRef.completedId.c_str(), installSubRef.applicationInfo.c_str());

                            d->m_refDownloadList.push_back(installSubRef);
                        }
                    }
                }
            }
        }
    }

    return true;
}
