#include "KMRemoteSummary.h"

#include "common/KMLogger.h"

class KMRemoteSummary::Private
{
public:
};

KMRemoteSummary::KMRemoteSummary()
    : d(make_shared<Private>())
{
}

KMRemoteSummary::~KMRemoteSummary() { }

/**
 * @brief 通过 curl 命令行下载文件
 *
 * @param url 下载的文件链接
 * @param outputFile  存储到本地的文件路径
 * @return true 下载成功
 * @return false 下载失败
 */
bool KMRemoteSummary::curlCmdDownload(string url, string outputFile)
{
    string curlCmd = "curl -o " + outputFile + " -L -f " + url;

    int curlRes = system(curlCmd.c_str());
    if (curlRes != 0)
    {
        kmlogger.error("Failed to download %s file, please check the url(%s) and try again!", outputFile.c_str(), url.c_str());
        return false;
    }
    return true;
}

/**
 * 回调函数，用于处理下载的数据
 */
size_t KMRemoteSummary::WriteCallback(void *contents, size_t size, size_t nmemb, string *buffer)
{
    size_t totalSize = size * nmemb;
    buffer->append(static_cast<char *>(contents), totalSize);
    return totalSize;
}

/**
 * @brief 通过 curl api 下载文件
 *
 * @param url 下载的文件链接
 * @param outputFile 存储到本地的文件名
 * @return true 下载成功
 * @return false 下载失败
 */
bool KMRemoteSummary::curlApiDownload(string url, string outputFile)
{
    // 初始化 libcurl
    CURL *curl = curl_easy_init();
    if (!curl)
    {
        kmlogger.error("Failed to initialize libcurl.");
        return false;
    }

    // 打开文件用于保存下载的数据
    FILE *file = fopen(outputFile.c_str(), "wb");
    if (!file)
    {
        kmlogger.error("Failed to open %s file for writing!", outputFile.c_str());
        curl_easy_cleanup(curl);
        return false;
    }

    // 设置 libcurl 参数
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); // 设置超时时间为1秒

    // 执行请求
    CURLcode res = curl_easy_perform(curl);

    // 关闭文件
    fclose(file);

    // 校验下载结果
    if (res != CURLE_OK)
    {
        // 检查是否因为超时而中断
        if (res == CURLE_OPERATION_TIMEDOUT)
        {
            kmlogger.error("Failed to download file, Operation timed out.");
        }
        else
        {
            kmlogger.error("Failed to download file");
        }
        return false;
    }

    // 清理 libcurl
    curl_easy_cleanup(curl);

    return true;
}

/**
 * @brief 通过 curl api 下载二进制文件，比如 .gz 格式压缩文件
 *
 * @param url 下载的文件链接
 * @param outputFileName 输出本地的压缩文件名
 * @return true
 * @return false
 */
bool KMRemoteSummary::curlApiDownloadBinaryGZFile(const string &url, const string &outputFileName)
{
    CURL *curl = curl_easy_init();
    if (!curl)
    {
        kmlogger.error("Failed to init curl!");
        return false;
    }

    std::string receivedData;
    std::ofstream outputFile(outputFileName, std::ios::binary);

    if (!outputFile.is_open())
    {
        kmlogger.error("Failed to open %s file!", outputFileName.c_str());
        return false;
    }

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &receivedData);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); // 设置超时时间为1秒

    CURLcode res = curl_easy_perform(curl);

    if (res != CURLE_OK)
    {
        // 检查是否因为超时而中断
        if (res == CURLE_OPERATION_TIMEDOUT)
        {
            kmlogger.error("Failed to download file, Operation timed out.");
        }
        else
        {
            kmlogger.error("Failed to download file");
        }
        return false;
    }

    outputFile.write(receivedData.c_str(), receivedData.size());

    curl_easy_cleanup(curl);
    outputFile.close();

    return true;
}

/**
 * @brief 解压缩 .gz 二进制压缩文件
 *
 * @param gzFileName .gz 压缩文件名
 * @param outputFileName 解压后的压缩文件名
 * @return true
 * @return false
 */
bool KMRemoteSummary::decompressGzFile(const std::string &gzFileName, const std::string &outputFileName)
{
    gzFile gzFile = gzopen(gzFileName.c_str(), "rb");
    if (!gzFile)
    {
        kmlogger.error("Failed to open %s file!", gzFileName.c_str());
        return false;
    }

    std::ofstream outputFile(outputFileName, std::ios::binary);
    if (!outputFile.is_open())
    {
        kmlogger.error("Failed to open file %s!", outputFileName.c_str());
        gzclose(gzFile);
        return false;
    }

    const int bufferSize = 8192;
    char buffer[bufferSize];

    int bytesRead;
    while ((bytesRead = gzread(gzFile, buffer, bufferSize)) > 0)
    {
        outputFile.write(buffer, bytesRead);
    }

    gzclose(gzFile);
    outputFile.close();

    return true;
}

/**
 * @brief 按字节从待解析二进制文件 kaiming-repo.idx 的起始位置 startPos，获取长度len的字节序，并存储在 outIndex 中
 *
 * @param filename 解析的kaiming-repo.idx 文件全路径名
 * @param startPos 解析outIndex的开始位置
 * @param len 解析的长度
 * @param outIndex 最终获取的32字节序
 * @return true 解析成功
 * @return false 解析失败
 */
bool KMRemoteSummary::getIndexFromParseSummaryIdxBinaryFile(string filename, int startPos, int len, string &outIndex)
{
    std::ifstream file(filename, std::ios::binary);
    if (!file.is_open())
    {
        kmlogger.error("Failed to open file %s", filename.c_str());
        return false;
    }

    // 定位到文件的起始位置
    file.seekg(startPos);

    // 设置输出的格式
    std::stringstream hexStream;
    hexStream << std::hex << std::setw(2) << std::setfill('0');

    // 逐字节读取文件并输出十六进制格式
    for (std::streamsize i = 0; i < len; ++i)
    {
        char byte;
        if (file.get(byte))
        {
            hexStream << static_cast<unsigned int>(static_cast<unsigned char>(byte));
        }
        else
        {
            kmlogger.error("Failed to read file %s", filename.c_str());
            return false;
        }
    }

    // 将字符串流内容复制到引用的字符串变量中
    outIndex = hexStream.str();

    file.close();

    return true;
}

/**
 * 根据下载的 summary.idx 获取架构(如 x86_64) 对应的 index commit
 */
bool KMRemoteSummary::parseSummaryIdxForRef(KMCommonRef &ref)
{
    char *path = (char *)ref.summaryIdxPath.c_str();

    GMappedFile *mfile = NULL;
    GBytes *mapFileBytes = NULL;
    char *sha256 = NULL;

    mfile = g_mapped_file_new(path, FALSE, NULL);
    if (mfile == NULL)
    {
        kmlogger.error("Failed to create mapped file!");
        return false;
    }
    mapFileBytes = g_mapped_file_get_bytes(mfile);
    sha256 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA256, mapFileBytes); // index: 5d8e4966ad282f50f138671397263ccee6866c4666b9f6c172e7609f3462a533
    kmlogger.info("File summary.idx content sha256:  %s", sha256);         // 对于 summary.idx 获取的是字节流对应的sha256,而不是由架构x86_64指定的index commit

    GVariant *subsummaryInfoVGVariant;
    GVariant *stateIndexGVariant;
    stateIndexGVariant = g_variant_ref_sink(g_variant_new_from_bytes(KAIMING_SUMMARY_INDEX_GVARIANT_FORMAT, mapFileBytes, FALSE));
    VarSummaryIndexRef index = varSummaryIndexFromGvariant(stateIndexGVariant);
    VarSummaryIndexSubsummariesRef subsummaries = varSummaryIndexGetSubsummaries(index);
    gsize subsummariesLSize = varSummaryIndexSubsummariesGetLength(subsummaries);
    kmlogger.info("%d: subsummariesLSize=%d ============ ", __LINE__, (int)subsummariesLSize);

    for (gsize i = 0; i < subsummariesLSize; i++)
    {
        VarSummaryIndexSubsummariesEntryRef entry = varSummaryIndexSubsummariesGetAt(subsummaries, i);
        const char *name = varSummaryIndexSubsummariesEntryGetKey(entry);
        kmlogger.info("%d: name: %s", __LINE__, name);

        VarSubsummaryRef subsummary = varSummaryIndexSubsummariesEntryGetValue(entry);
        gsize checksumBytesLen;
        const char *dash, *subsummaryArch;

        dash = strchr(name, '-');
        subsummaryArch = dash == NULL ? name : dash + 1;
        kmlogger.info("%d: subsummaryArch: %s", __LINE__, subsummaryArch);

        if (dash == NULL) /* No subset */
        {
        }
        else /* Subset */
        {
            continue;
        }

        kmlogger.debug("\n %s:%d %s got_summary peek_checksum insert state->index_ht ysq", __FILE__, __LINE__, __func__);
        varSubsummaryPeekChecksum(subsummary, &checksumBytesLen);
        if (G_UNLIKELY(checksumBytesLen != OSTREE_SHA256_DIGEST_LEN))
        {
            kmlogger.info("Invalid checksum for digested summary, not using cache");
            continue;
        }
        subsummaryInfoVGVariant = varSubsummaryToOwnedGvariant(subsummary, stateIndexGVariant);
    }

    VarRefInfoRef info;
    GVariant *summary = NULL;

    // g_hash_table_insert (progressStatus.subsummaries, g_strdup (arch), subsummary);
    // summary = g_variant_ref_sink(g_variant_new_from_bytes(OSTREE_SUMMARY_GVARIANT_FORMAT, mapFileBytes, FALSE));

    VarSubsummaryRef subsummaryInfo;
    gsize checksumBytesLen;
    const guchar *checksumBytes;
    g_autofree char *checksum = NULL;
    g_autofree char *cacheName = NULL;

    subsummaryInfo = varSubsummaryFromGvariant(subsummaryInfoVGVariant);
    checksumBytes = varSubsummaryPeekChecksum(subsummaryInfo, &checksumBytesLen);
    kmlogger.info("%d: checksumBytes=%s \n checksumBytesLen:%d", __LINE__, (char *)checksumBytes, (int)(checksumBytesLen));

    checksum = ostree_checksum_from_bytes(checksumBytes);
    kmlogger.info("%d: checksum:%s checksumBytesLen=%d", __LINE__, checksum, (int)checksumBytesLen);

    ref.repoSummaryIndex = string(checksum);

    return true;
}

/**
 * 根据下载的 summary.idx 获取架构(如 x86_64) 对应的 index commit
 */
bool KMRemoteSummary::parseSummaryIdxFromPath(string summaryIdxPath, string &outIndex)
{
    char *path = (char *)summaryIdxPath.c_str();

    GMappedFile *mfile = NULL;
    GBytes *mapFileBytes = NULL;
    char *sha256 = NULL;

    mfile = g_mapped_file_new(path, FALSE, NULL);
    if (mfile == NULL)
    {
        kmlogger.error("Failed to create mapped file!");
        outIndex = "";
        return false;
    }
    mapFileBytes = g_mapped_file_get_bytes(mfile);
    sha256 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA256, mapFileBytes); // index: 5d8e4966ad282f50f138671397263ccee6866c4666b9f6c172e7609f3462a533
    kmlogger.info("File summary.idx content sha256:  %s", sha256);         // 对于 summary.idx 获取的是字节流对应的sha256,而不是由架构x86_64指定的index commit

    GVariant *subsummaryInfoVGVariant;
    GVariant *stateIndexGVariant;
    stateIndexGVariant = g_variant_ref_sink(g_variant_new_from_bytes(KAIMING_SUMMARY_INDEX_GVARIANT_FORMAT, mapFileBytes, FALSE));
    VarSummaryIndexRef index = varSummaryIndexFromGvariant(stateIndexGVariant);
    VarSummaryIndexSubsummariesRef subsummaries = varSummaryIndexGetSubsummaries(index);
    gsize subsummariesLSize = varSummaryIndexSubsummariesGetLength(subsummaries);
    kmlogger.info("%d: subsummariesLSize=%d ============ ", __LINE__, (int)subsummariesLSize);

    for (gsize i = 0; i < subsummariesLSize; i++)
    {
        VarSummaryIndexSubsummariesEntryRef entry = varSummaryIndexSubsummariesGetAt(subsummaries, i);
        const char *name = varSummaryIndexSubsummariesEntryGetKey(entry);
        kmlogger.info("%d: name: %s", __LINE__, name);

        VarSubsummaryRef subsummary = varSummaryIndexSubsummariesEntryGetValue(entry);
        gsize checksumBytesLen;
        const char *dash, *subsummaryArch;

        dash = strchr(name, '-');
        subsummaryArch = dash == NULL ? name : dash + 1;
        kmlogger.info("%d: subsummaryArch: %s", __LINE__, subsummaryArch);

        if (dash == NULL) /* No subset */
        {
        }
        else /* Subset */
        {
            continue;
        }

        kmlogger.debug(" %s:%d %s got_summary peek_checksum insert state->index_ht ysq", __FILE__, __LINE__, __func__);
        varSubsummaryPeekChecksum(subsummary, &checksumBytesLen);
        if (G_UNLIKELY(checksumBytesLen != OSTREE_SHA256_DIGEST_LEN))
        {
            kmlogger.info("Invalid checksum for digested summary, not using cache");
            continue;
        }
        subsummaryInfoVGVariant = varSubsummaryToOwnedGvariant(subsummary, stateIndexGVariant);
    }

    VarRefInfoRef info;
    GVariant *summary = NULL;

    // g_hash_table_insert (progressStatus.subsummaries, g_strdup (arch), subsummary);
    // summary = g_variant_ref_sink(g_variant_new_from_bytes(OSTREE_SUMMARY_GVARIANT_FORMAT, mapFileBytes, FALSE));

    VarSubsummaryRef subsummaryInfo;
    gsize checksumBytesLen;
    const guchar *checksumBytes;
    g_autofree char *checksum = NULL;
    g_autofree char *cacheName = NULL;

    subsummaryInfo = varSubsummaryFromGvariant(subsummaryInfoVGVariant);
    checksumBytes = varSubsummaryPeekChecksum(subsummaryInfo, &checksumBytesLen);
    kmlogger.debug("%d: checksumBytes=%s \n checksumBytesLen:%d", __LINE__, (char *)checksumBytes, (int)(checksumBytesLen));

    checksum = ostree_checksum_from_bytes(checksumBytes);
    kmlogger.info("%d: checksum:%s checksumBytesLen=%d", __LINE__, checksum, (int)checksumBytesLen);

    outIndex = string(checksum);
    return true;
}

/**
 * @brief 根据文件名获取subsummary
 *
 * @param summaryFilePath
 * @return GVariant*
 */
GVariant *KMRemoteSummary::getSummary(string summaryFilePath)
{
    char *path = (char *)summaryFilePath.c_str();

    GMappedFile *mfile = NULL;
    GBytes *mapFileBytes = NULL;
    char *sha256 = NULL;

    // GFile *subCacheFile = g_file_new_for_path(path);
    // mfile = g_mapped_file_new(getFilePathCached(subCacheFile), FALSE, NULL);
    mfile = g_mapped_file_new(path, FALSE, NULL);
    if (mfile == NULL)
    {
        kmlogger.error("Failed to create mapped file!");
        return NULL;
    }
    mapFileBytes = g_mapped_file_get_bytes(mfile);
    sha256 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA256, mapFileBytes); // index: 5d8e4966ad282f50f138671397263ccee6866c4666b9f6c172e7609f3462a533

    kmlogger.info("file sha256:  %s", sha256);

    VarRefInfoRef info;
    GVariant *summary = NULL;

    // g_hash_table_insert (progressStatus.subsummaries, g_strdup (arch), subsummary);
    summary = g_variant_ref_sink(g_variant_new_from_bytes(OSTREE_SUMMARY_GVARIANT_FORMAT, mapFileBytes, FALSE));

    return summary;
}

/**
 * @brief 根据文件名获取subsummary
 *
 * @param ref
 * @return GVariant*
 */
GVariant *KMRemoteSummary::getSummaryForRef(KMCommonRef &ref)
{
    char *path = (char *)ref.repoSummaryPath.c_str();

    GMappedFile *mfile = NULL;
    GBytes *mapFileBytes = NULL;
    char *sha256 = NULL;

    // GFile *subCacheFile = g_file_new_for_path(path);
    // mfile = g_mapped_file_new(getFilePathCached(subCacheFile), FALSE, NULL);
    mfile = g_mapped_file_new(path, FALSE, NULL);
    if (mfile == NULL)
    {
        kmlogger.error("Failed to create mapped file!");
        return NULL;
    }
    mapFileBytes = g_mapped_file_get_bytes(mfile);
    sha256 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA256, mapFileBytes); // index: 5d8e4966ad282f50f138671397263ccee6866c4666b9f6c172e7609f3462a533

    kmlogger.info("file sha256: %s", sha256);

    VarRefInfoRef info;
    GVariant *summary = NULL;

    // g_hash_table_insert (progressStatus.subsummaries, g_strdup (arch), subsummary);
    summary = g_variant_ref_sink(g_variant_new_from_bytes(OSTREE_SUMMARY_GVARIANT_FORMAT, mapFileBytes, FALSE));
    ref.subsummary = summary;

    return summary;
}

/**
 * @brief 根据文件名获取subsummary
 *
 * @param ref
 * @return GVariant*
 */
GVariant *KMRemoteSummary::getSummaryFromPath(string subsummaryPath)
{
    char *path = (char *)subsummaryPath.c_str();

    GMappedFile *mfile = NULL;
    GBytes *mapFileBytes = NULL;
    char *sha256 = NULL;

    // GFile *subCacheFile = g_file_new_for_path(path);
    // mfile = g_mapped_file_new(getFilePathCached(subCacheFile), FALSE, NULL);
    mfile = g_mapped_file_new(path, FALSE, NULL);
    if (mfile == NULL)
    {
        kmlogger.error("Failed to create mapped file!");
        return NULL;
    }
    mapFileBytes = g_mapped_file_get_bytes(mfile);
    sha256 = g_compute_checksum_for_bytes(G_CHECKSUM_SHA256, mapFileBytes); // index: 5d8e4966ad282f50f138671397263ccee6866c4666b9f6c172e7609f3462a533

    kmlogger.info("file sha256: %s", sha256);

    VarRefInfoRef info;
    GVariant *summary = NULL;

    // g_hash_table_insert (progressStatus.subsummaries, g_strdup (arch), subsummary);
    summary = g_variant_ref_sink(g_variant_new_from_bytes(OSTREE_SUMMARY_GVARIANT_FORMAT, mapFileBytes, FALSE));

    return summary;
}

/**
 * @brief 遍历index.sub 文件，获取 commitid 信息
 *
 * @param summaryVGvariant index.sub 的 (GVariant *)数据
 * @param collection_id 仓库的collection_id，此处为空
 * @param ref appref, 如  app/org.kde.kclock/x86_64/master
 * @param outChecksum 返回的 commitid 信息
 * @param outInfo
 * @return true
 * @return false
 */
bool KMRemoteSummary::summaryLookupRefCommitAndInfo(GVariant *summaryVGvariant, const char *collection_id, const char *ref, char **outChecksum, VarRefInfoRef *outInfo)
{
    kmlogger.debug("lookup ref: ", ref); // 此处对于没有commitid的ref总是空值
    VarSummaryRef summary;
    VarRefMapRef varRefMap;
    VarRefInfoRef info;
    const guchar *checksumBytes;
    gsize checksumBytesLen;

    summary = varSummaryFromGvariant(summaryVGvariant);

    if (!summaryFindRefMap(summary, collection_id, &varRefMap))
    {
        kmlogger.error("Failed to find ref map!");
        return false;
    }

    if (!varRefMapLookupRef(varRefMap, ref, &info))
    {
        kmlogger.error("Failed to lookup ref!");
        return false;
    }

    kmlogger.info("begin to get checksumBytes");
    checksumBytes = varRefInfoPeekChecksum(info, &checksumBytesLen);
    if (G_UNLIKELY(checksumBytesLen != OSTREE_SHA256_DIGEST_LEN))
    {
        kmlogger.error("sha256 digest len is not match.");
        return false;
    }

    if (outChecksum)
    {
        *outChecksum = ostree_checksum_from_bytes(checksumBytes);
        kmlogger.info("outChecksum:  %s", *outChecksum);
    }

    if (outInfo)
    {
        *outInfo = info;
    }

    return true;
}

bool KMRemoteSummary::summaryFindRefMap(VarSummaryRef summary, const char *collection_id, VarRefMapRef *refsOut)
{
    VarMetadataRef metadata = varSummaryGetMetadata(summary);
    const char *summaryCollectionId;

    summaryCollectionId = varMetadataLookupString(metadata, "ostree.summary.collection-id", NULL);

    if (collection_id == NULL || g_strcmp0(collection_id, summaryCollectionId) == 0)
    {
        if (refsOut)
        {
            *refsOut = varSummaryGetRefMap(summary);
        }
        return true;
    }
    else if (collection_id != NULL)
    {
        VarVariantRef collectionMapVariant;
        if (varMetadataLookup(metadata, "ostree.summary.collection-map", NULL, &collectionMapVariant))
        {
            VarCollectionMapRef collectionMap = varCollectionMapFromVariant(collectionMapVariant);
            return varCollectionMapLookup(collectionMap, collection_id, NULL, refsOut);
        }
    }

    return false;
}

/**
 * @brief This special cases the ref lookup which by doing a bsearch since the array is sorted
 *
 * @param varRefMap
 * @param ref
 * @param outInfo
 * @return true
 * @return false
 */
bool KMRemoteSummary::varRefMapLookupRef(VarRefMapRef varRefMap, const char *ref, VarRefInfoRef *outInfo)
{
    int imax, imin;
    int imid;
    int n;

    g_return_val_if_fail(outInfo != NULL, FALSE);

    n = varRefMapGetLength(varRefMap);
    if (n == 0)
    {
        return false;
    }

    imax = n - 1;
    imin = 0;
    while (imax >= imin)
    {
        VarRefMapEntryRef entry;
        const char *cur;
        int cmp;

        imid = (imin + imax) / 2;

        entry = varRefMapGetAt(varRefMap, imid);
        cur = varRefMapEntryGetRef(entry);

        cmp = strcmp(cur, ref);
        if (cmp < 0)
        {
            imin = imid + 1;
        }
        else if (cmp > 0)
        {
            if (imid == 0)
            {
                break;
            }
            imax = imid - 1;
        }
        else
        {
            *outInfo = varRefMapEntryGetInfo(entry);
            return true;
        }
    }

    return false;
}

guint64 KMRemoteSummary::getTimestampFromRefInfo(VarRefInfoRef info)
{
    VarMetadataRef metadata = varRefInfoGetMetadata(info);
    return GUINT64_FROM_BE(varMetadataLookupUint64(metadata, OSTREE_COMMIT_TIMESTAMP2, 0));
}

/**
 * @brief 获取当前 ref 的相关信息，比如安装大小和相关键值对信息
 * @param summaryVGvariant
 * @param ref
 * @param commitDataGVariant
 * @param outDownloadSize
 * @param outInstalledSize 安装包的大小，单位为B
 * @param outMetadata 安装包的相关信息
 * @return true
 * @return false
 */
bool KMRemoteSummary::summarySideloadRemoteState(GVariant *commitDataGVariant, guint64 *outDownloadSize, guint64 *outInstalledSize, const char **outMetadata)
{
    g_autoptr(GBytes) metadataBytes = nullptr;
    g_autoptr(GVariant) commitMetadataGVariant = nullptr;
    const char *pXaMetadata = nullptr;
    guint64 downloadSize = 0;
    guint64 installedSize = 0;

    if (commitDataGVariant == nullptr)
    {
        return false;
    }

    commitMetadataGVariant = g_variant_get_child_value(commitDataGVariant, 0);
    g_variant_lookup(commitMetadataGVariant, "xa.metadata", "&s", &pXaMetadata);
    if (pXaMetadata == nullptr)
    {
        return false;
    }

    if (outMetadata)
    {
        *outMetadata = pXaMetadata;
    }

    metadataBytes = g_bytes_new(pXaMetadata, strlen(pXaMetadata));
    if (g_variant_lookup(commitMetadataGVariant, "xa.download-size", "t", &downloadSize))
    {
        *outDownloadSize = GUINT64_FROM_BE(downloadSize);
    }
    if (g_variant_lookup(commitMetadataGVariant, "xa.installed-size", "t", &installedSize))
    {
        *outInstalledSize = GUINT64_FROM_BE(installedSize);
    }

    return true;
}

/**
 * @brief 获取当前 ref 的相关信息，比如安装大小和相关键值对信息
 *
 * @param summaryVGvariant
 * @param ref
 * @param outDownloadSize
 * @param outInstalledSize 安装包的大小，单位为B
 * @param outMetadata 安装包的相关信息
 * @return true
 * @return false
 */
bool KMRemoteSummary::summaryRemoteStateLookupCache(GVariant *summaryVGvariant, const char *ref, guint64 *outDownloadSize, guint64 *outInstalledSize, const char **outMetadata)
{
    VarCacheDataRef cacheData;
    VarMetadataRef meta;
    VarSummaryRef summaryRef;
    int summaryVersion;

    summaryRef = varSummaryFromGvariant(summaryVGvariant);
    meta = varSummaryGetMetadata(summaryRef);

    summaryVersion = (int)GUINT32_FROM_LE(varMetadataLookupUint32(meta, "xa.summary-version", 0));

    kmlogger.info("summaryVersion:  %d", summaryVersion);
    if (summaryVersion == 0)
    {
        VarCacheRef cache;
        int pos;
        VarVariantRef cacheVarVariant;
        VarVariantRef cacheVar;

        if (!varMetadataLookup(meta, "xa.cache", NULL, &cacheVarVariant))
        {
            kmlogger.error("No summary or Kaiming cache available for remote kaiming-repo!");
            return false;
        }
    }
    else if (summaryVersion == 1)
    {
        VarRefMapRef varRefMap = varSummaryGetRefMap(summaryRef);
        VarRefInfoRef info;
        VarMetadataRef commitMetadataGVariant;
        VarVariantRef cacheDataVariant;

        if (!varRefMapLookupRef(varRefMap, ref, &info))
        {
            kmlogger.error("No entry for %s in remote %s summary cache!", ref, REPO_NAME);
            return false;
        }

        commitMetadataGVariant = varRefInfoGetMetadata(info);
        if (!varMetadataLookup(commitMetadataGVariant, "xa.data", NULL, &cacheDataVariant))
        {
            kmlogger.error("Missing xa.data in summary for remote %s", REPO_NAME);
            return false;
        }
        cacheData = varCacheDataFromVariant(cacheDataVariant);
    }
    else
    {
        kmlogger.error("Unsupported summary version %d for remote %s", summaryVersion, REPO_NAME);
        return false;
    }

    if (outInstalledSize)
    {
        // 软件包大小
        *outInstalledSize = varCacheDataGetInstalledSize(cacheData);
        kmlogger.info("outInstalledSize:  %ld", (long)*outInstalledSize);
    }

    if (outDownloadSize)
    {
        // 更新包大小
        *outDownloadSize = varCacheDataGetDownloadSize(cacheData);
        kmlogger.info("outDownloadSize:  %ld", (long)*outDownloadSize);
    }

    if (outMetadata)
    {
        *outMetadata = varCacheDataGetMetadata(cacheData);
        // std::cout << "outMetadata = " << *outMetadata << std::endl;
    }

    return true;
}

/**
 * @brief 通过 matchRef 进行逐个匹配 (GVariant *)index.sub 的appid
 *
 * @param summaryVGvariant
 * @param optCollectionId
 * @param matchRef
 * @param outRef
 * @return true
 * @return false
 */
bool KMRemoteSummary::findRefFromRemoteSummary(GVariant *summaryVGvariant, const char *optCollectionId, string matchRef, char **outRef)
{
    int len, i;

    VarSummaryRef summary;
    VarMetadataRef exts;
    VarRefMapRef varRefMap;
    VarVariantRef v;

    summary = varSummaryFromGvariant(summaryVGvariant);
    varRefMap = varSummaryGetRefMap(summary);
    len = varRefMapGetLength(varRefMap);

    kmlogger.info("%d matchRef: %s", __LINE__, matchRef.c_str());

    for (i = 0; i < len; i++)
    {
        VarRefMapEntryRef entry = varRefMapGetAt(varRefMap, i);
        const char *refName = varRefMapEntryGetRef(entry);
        kmlogger.info("%d refName = %s", __LINE__, refName);

        if (strcmp(matchRef.c_str(), refName) == 0)
        {
            *outRef = g_strdup(refName);
            return true;
        }
    }

    if (i == len)
    {
        return false;
    }

    return true;
}

/**
 * @brief 通过 matchRef 进行逐个匹配 (GVariant *)index.sub 的appid,并将结果输出到 outRefs中
 *
 * @param summaryVGvariant
 * @param optCollectionId
 * @param matchRef refid格式为: org.kde.kclock
 * @param outRef
 * @return true
 * @return false
 */
bool KMRemoteSummary::findRefVectorFromRemoteSummary(GVariant *summaryVGvariant, const char *optCollectionId, string matchRef, vector<string> &outRefs)
{
    int len, i;
    bool findRefFlag = false; // 是否找到匹配的ref

    VarSummaryRef summary;
    VarMetadataRef exts;
    VarRefMapRef varRefMap;
    VarVariantRef v;

    summary = varSummaryFromGvariant(summaryVGvariant);

    if (optCollectionId != nullptr)
    {
        exts = varSummaryGetMetadata(summary);
        if (varMetadataLookup(exts, "ostree.summary.collection-map", nullptr, &v))
        {
            VarCollectionMapRef map = varCollectionMapFromVariant(v);
            if (varCollectionMapLookup(map, optCollectionId, nullptr, &varRefMap))
            {
                int len = varRefMapGetLength(varRefMap);
                for (int i = 0; i < len; i++)
                {
                    VarRefMapEntryRef entry = varRefMapGetAt(varRefMap, i);
                    string refName = varRefMapEntryGetRef(entry);
                    if (refName.find(matchRef) != std::string::npos)
                    {
                        // 找到匹配的ref，并不退出，而是保存到向量中
                        outRefs.push_back(refName);
                        findRefFlag = true;
                    }
                }
            }
        }
    }
    else
    {
        varRefMap = varSummaryGetRefMap(summary);
        len = varRefMapGetLength(varRefMap);

        kmlogger.info("%d matchRef: %s", __LINE__, matchRef.c_str());

        for (i = 0; i < len; i++)
        {
            VarRefMapEntryRef entry = varRefMapGetAt(varRefMap, i);
            const char *refNameVar = varRefMapEntryGetRef(entry);
            string refName = string(refNameVar);
            kmlogger.debug("%d refName = %s", __LINE__, refName.c_str());

            if (refName.find(matchRef) != std::string::npos)
            {
                // 找到匹配的ref，并不退出，而是保存到向量中
                outRefs.push_back(refName);
                findRefFlag = true;
            }
        }
    }

    if (!findRefFlag)
    {
        return false;
    }

    return true;
}

/**
 * @brief 通过 matchRef 进行逐个匹配 (GVariant *)index.sub 的ref
 *
 *
 * @param summaryVGvariant
 * @param optCollectionId
 * @param matchRef  ref格式为: app/org.kde.kclock/x86_64/stable
 * @return true 已找到ref
 * @return false 未找到
 */
bool KMRemoteSummary::findRefFromRemoteSummary(GVariant *summaryVGvariant, const char *optCollectionId, string matchRef)
{
    int len, i;
    bool findRefFlag = false; // 是否找到匹配的ref

    VarSummaryRef summary;
    VarMetadataRef exts;
    VarRefMapRef varRefMap;
    VarVariantRef v;

    summary = varSummaryFromGvariant(summaryVGvariant);

    if (optCollectionId != nullptr)
    {
        exts = varSummaryGetMetadata(summary);
        if (varMetadataLookup(exts, "ostree.summary.collection-map", nullptr, &v))
        {
            VarCollectionMapRef map = varCollectionMapFromVariant(v);
            if (varCollectionMapLookup(map, optCollectionId, nullptr, &varRefMap))
            {
                int len = varRefMapGetLength(varRefMap);
                for (int i = 0; i < len; i++)
                {
                    VarRefMapEntryRef entry = varRefMapGetAt(varRefMap, i);
                    string refName = varRefMapEntryGetRef(entry);
                    if (refName.find(matchRef) != std::string::npos)
                    {
                        // 找到匹配的ref，并不退出，而是保存到向量中
                        findRefFlag = true;
                        break;
                    }
                }
            }
        }
    }
    else
    {
        varRefMap = varSummaryGetRefMap(summary);
        len = varRefMapGetLength(varRefMap);

        kmlogger.info("%d matchRef: %s", __LINE__, matchRef.c_str());

        for (i = 0; i < len; i++)
        {
            VarRefMapEntryRef entry = varRefMapGetAt(varRefMap, i);
            const char *refNameVar = varRefMapEntryGetRef(entry);
            string refName = string(refNameVar);
            kmlogger.debug("%d refName = %s", __LINE__, refName.c_str());

            if (refName.find(matchRef) != std::string::npos)
            {
                // 找到匹配的ref，并不退出，而是保存到向量中
                kmlogger.info("found ref, refName:%s matchRef:%s", refName.c_str(), matchRef.c_str());
                findRefFlag = true;
                break;
            }
        }
    }

    if (!findRefFlag)
    {
        return false;
    }

    return true;
}

/**
 * @brief 获取ref包含 .default 或 .Debug 相关的子ref序列
 *
 * @param summaryVGvariant index.sub 的 (GVariant *)数据
 * @param collection_id 仓库的collection_id，此处为空
 * @param ref appref, 如  runtime/org.freedesktop.Platform.GL/x86_64/22.08
 * @param refId app ref id, 如 org.freedesktop.Platform.GL
 * @param arch 架构名称，如 x86
 * @param branch 分支名，如 22.08;22.08-extra;1.4
 * @return vector<string> 返回的多个根据ref获取的子ref序列，如 runtime/org.freedesktop.Platform.GL.default/x86_64/22.08; runtime/org.freedesktop.Platform.GL.default/x86_64/22.08-extra
 */
vector<string> KMRemoteSummary::summaryMatchSubrefs(GVariant *summaryVGvariant, const char *collection_id, const char *ref, const char *refId, const char *arch, const char *branch)
{
    vector<string> res;
    int n, i;
    char *partsPrefix = NULL;
    char *refPrefix = NULL;
    char *refSuffix = NULL;
    VarSummaryRef summary;
    VarRefMapRef varRefMap;

    summary = varSummaryFromGvariant(summaryVGvariant);
    if (summaryFindRefMap(summary, NULL, &varRefMap))
    {
        /* Match against the refs. */
        partsPrefix = g_strconcat(refId, ".", NULL);

        refPrefix = g_strconcat("runtime", "/", NULL);
        refSuffix = g_strconcat("/", arch, "/", branch, NULL);

        n = varRefMapGetLength(varRefMap);

        // id:runtime/org.freedesktop.Platform.GL/x86_64/23.08 arch:x86_64 branch:23.08
        // partsPrefix:org.freedesktop.Platform.GL. refPrefix:runtime/ refSuffix:/x86_64/23.08 n=12833
        kmlogger.info("id:%s arch:%s branch:%s partsPrefix:%s refPrefix:%s refSuffix:%s n=%ld", ref, arch, branch, partsPrefix, refPrefix, refSuffix, n);

        for (i = 0; i < n; i++)
        {
            VarRefMapEntryRef entry = varRefMapGetAt(varRefMap, i);
            const char *cur;
            const char *idStartVar;
            const char *idSuffixVar;
            const char *idEndVar;

            cur = varRefMapEntryGetRef(entry);
            kmlogger.debug("i=%d refPrefix:%s cur ref:%s ", i, refPrefix, cur); // refPrefix:runtime/ cur ref:runtime/org.kde.Platform/x86_64/5.15

            if (strstr(cur, ".Debug") != NULL || strstr(cur, ".Sources") != NULL)
            {
                // 过滤掉 .Debug, .Sources 相关包
                continue;
            }

            /* Must match type */
            if (!g_str_has_prefix(cur, refPrefix))
            {
                continue;
            }

            /* Must match arch & branch */
            if (!g_str_has_suffix(cur, refSuffix))
            {
                continue;
            }

            kmlogger.info("i=%d refSuffix:%s select cur ref:%s ", i, refSuffix, cur);

            idStartVar = strchr(cur, '/');
            if (idStartVar == NULL)
            {
                continue;
            }
            idStartVar += 1;

            idEndVar = strchr(idStartVar, '/');
            if (idEndVar == NULL)
            {
                continue;
            }

            /* But only prefix of id */
            if (!g_str_has_prefix(idStartVar, partsPrefix))
            {
                continue;
            }

            /* And no dots (we want to install prefix.$ID, but not prefix.$ID.Sources) */
            idSuffixVar = idStartVar + strlen(partsPrefix);
            if (memchr(idSuffixVar, '.', idEndVar - idSuffixVar) != NULL)
            {
                continue;
            }

            kmlogger.info("select cur ref:%s ", cur);
            res.push_back(string(cur));
        }
    }

    return res;
}

/**
 * @brief 离线包中查找
 * @param varRefMap
 * @param ref
 * @param outInfo
 * @return true
 * @return false
 */
bool KMRemoteSummary::sileloadVarRefMapLookupRef(VarRefMapRef varRefMap, const vector<string> &vecFindRef, string &ref, VarRefInfoRef *outInfo)
{
    string strRef = ref;
    int pos = strRef.find("/");
    if (pos == string::npos)
    {
        return false;
    }
    int pos1 = strRef.find("/", pos + 1);
    if (pos1 == string::npos)
    {
        return false;
    }

    strRef = strRef.substr(0, pos1);
    int n = varRefMapGetLength(varRefMap);
    if (n == 0)
    {
        return false;
    }

    for (int i = 0; i < n; i++)
    {
        VarRefMapEntryRef entry;
        entry = varRefMapGetAt(varRefMap, i);
        string cur;
        cur.assign(varRefMapEntryGetRef(entry));

        if (cur.compare(0, strRef.length(), strRef) != 0)
        {
            continue;
        }

        if (find(vecFindRef.begin(), vecFindRef.end(), cur) != vecFindRef.end())
        {
            continue;
        }

        ref = cur;
        *outInfo = varRefMapEntryGetInfo(entry);
        return true;
    }

    return false;
}

/**
 * @brief 离线包获取ref,commint,info
 * @param summaryVGvariant index.sub 的 (GVariant *)数据
 * @param collection_id 仓库的collection_id，此处为空
 * @param ref appref, 如  app/org.kde.kclock/x86_64/master
 * @param outChecksum 返回的 commitid 信息
 * @param outInfo
 * @return true
 * @return false
 */
bool KMRemoteSummary::sideloadSummaryLookupRefCommitAndInfo(GVariant *summaryVGvariant, const char *collection_id, const vector<string> &vFindRef, string &ref, char **outChecksum, VarRefInfoRef *outInfo)
{
    kmlogger.debug("lookup ref: ", ref); // 此处对于没有commitid的ref总是空值
    VarSummaryRef summary;
    VarRefMapRef varRefMap;
    VarRefInfoRef info;
    const guchar *checksumBytes;
    gsize checksumBytesLen;

    summary = varSummaryFromGvariant(summaryVGvariant);

    if (!summaryFindRefMap(summary, collection_id, &varRefMap))
    {
        kmlogger.error("Failed to find ref map!");
        return false;
    }

    if (!sileloadVarRefMapLookupRef(varRefMap, vFindRef, ref, &info))
    {
        kmlogger.error("Failed to lookup ref!");
        return false;
    }

    kmlogger.info("begin to get checksumBytes");
    checksumBytes = varRefInfoPeekChecksum(info, &checksumBytesLen);
    if (G_UNLIKELY(checksumBytesLen != OSTREE_SHA256_DIGEST_LEN))
    {
        kmlogger.error("sha256 digest len is not match.");
        return false;
    }

    if (outChecksum)
    {
        *outChecksum = ostree_checksum_from_bytes(checksumBytes);
        kmlogger.info("outChecksum:  %s", *outChecksum);
    }

    if (outInfo)
    {
        *outInfo = info;
    }

    return true;
}