#include "KMInfoCommand.h"

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

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

#include "common/KMBuildinsUtils.h"
#include "common/KMConfig.h"
#include "common/KMError.h"
#include "common/KMFile.h"
#include "common/KMJsonHelper.h"
#include "common/KMLogger.h"
#include "common/KMOptions.h"
#include "common/KMUtil.h"
#include "common/kmtranslation.h"
#include "common/KMInfoJson.h"
#define YELLOW_COLOR 33

class KMInfoCommand::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;
    std::string m_remote;
    std::string m_arch;
    // vector<string> m_vecRefs;

    bool m_onlyShowCommit = false;
    bool m_onlyShowMatadata = false;
    bool m_onlyShowLocation = false;
    std::string m_name;
    std::string m_branch;
};

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

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

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

/**
 * @brief 命令行参数添加描述选项
 */
void KMInfoCommand::Options::addOptions()
{
    m_optionsDescription = std::make_unique<opt::options_description>(_("\nUsage:\n \tkaiming info [OPTION…] (reference) - Get info about an app or runtime "));

    opt::options_description helpOptions(_("Help Options"));
    helpOptions.add_options()("help,h", _("Show help options"));
    helpOptions.add_options()("verbose,v", _("Provide detailed output information"));

    opt::options_description appOptions(_("Application Options"));
    // appOptions.add_options()("remote=kaiming-repo", opt::value<string>(&m_remote), _("Use this remote repo for info"))("show-commit,c", _("Show commit"))("show-location,l", _("Show location"))("show-metadata,m", _("Show metadata"));
    appOptions.add_options()("arch=ARCH", opt::value<string>(&m_arch), _("Specify architecture"));

    opt::options_description positionalOptions(_("Positional Options"));
    positionalOptions.add_options()("NAME", opt::value<std::string>(&m_name), _("The app id"));
    // positionalOptions.add_options()("BRANCH", opt::value<std::string>(&m_branch), _("The app branch"));

    m_optionsDescription->add(helpOptions).add(appOptions).add(positionalOptions);

    m_optionsPositionalDescription->add("NAME", 1);
    // m_optionsPositionalDescription->add("BRANCH", 1);
}

/**
 * @brief 命令行参数检查项
 */
void KMInfoCommand::Options::checkOptions(const opt::variables_map &varsMap)
{
    checkOption(varsMap, "help", "h", m_bHelp);
    checkOption(varsMap, "show-commit", "v", m_onlyShowCommit);
    checkOption(varsMap, "show-metadata", "m", m_onlyShowMatadata);
    checkOption(varsMap, "show-location", "l", m_onlyShowLocation);
}

class KMInfoCommand::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;
    std::shared_ptr<KMOSTreeHandler> m_ostreeHandler;

    KMLocalInfo m_localInfo;

    bool isRemoteApi = false; // 获取远程信息，供 dbus api调用
    KMLocalInfo m_remoteInfo;
    map<string, KMRef> m_remoteRefs; // 远程的软件包列表
    std::string m_arch;
    string m_remoteRepoName;
    std::string m_repoIndexUrl;
    std::string m_repoIndexLocalGzPath;
    std::string m_repoIndexLocalSubPath;
};

REGISTER_SUBCOMMAND_DYNCREATE(info, KMInfoCommand)

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

KMInfoCommand::~KMInfoCommand() {}

/**
 * @brief list 命令参数处理,不需要参数
 *
 * 列出所有已安装的软件包信息,只支持不含参数
 *
 * 使用实例:
 *      1. kaiming list
 *
 * @param argc
 * @param argv
 * @return int
 */
int KMInfoCommand::despose(int argc, char **argv)
{
    init();

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

    if (d->m_options->m_name.empty())
    {
        KMError("NAME or REF must be input!");
        return KM_ERROR_INVALID_ARGS;
    }

    int ret = start(d->m_options->m_name);

    return ret;
}

/**
 * @brief 列出所有的已安装软件包
 *
 *
 * @param name
 * @return int
 */
int KMInfoCommand::start(const std::string &name)
{
    string refId = name;
    kmlogger.info("refId: %s", refId.c_str());

    if (!isValidRefId(refId))
    {
        kmlogger.error("refId %s is invalid.", refId);
        return KM_ERROR_INVALID_ARGS;
    }

    if (d->m_options->m_remote == "kaiming-repo" || d->isRemoteApi)
    {
        // 获取远程仓库的信息，目前版本信息需要商店上架服务端给出,get post向服务端发送请求方式
        int ret = getRemoteInfoCommand(refId);

        return ret;
    }
    fs::path layersPath = d->m_folder->getLayersPath();

    findInfoJsonFiles(layersPath, "info.json", layersPath, refId);

    return KM_ERROR_NO;
}

/**
 * @brief Get the Remote Info object
 *
 * @param refId
 * @return int
 */
int KMInfoCommand::getRemoteInfoCommand(string refId)
{
    string completedRefId;
    string remoteCompleteRefId;
    bool isFound = false;

    KMCommonRef commonRef = makeRefDataFromRefId(refId, completedRefId);
    kmlogger.info("completedRefId: %s", completedRefId.c_str());

#if 0
    for (auto &remoteRef : d->m_remoteRefs)
    {
        kmlogger.info("remote info => baseType:%s common_baseType:%s id:%s arch:%s branch:%s"
                      , remoteRef.second.kind.c_str()
                      , commonRef.baseType.c_str()
                      , remoteRef.second.id.c_str()
                      , remoteRef.second.arch.c_str()
                      , remoteRef.second.branch.c_str()
                      );
        fs::path completeRefIdPath(remoteRef.second.kind);
        remoteCompleteRefId =  (completeRefIdPath / remoteRef.second.id / remoteRef.second.arch / remoteRef.second.branch).string();

        kmlogger.info("remoteCompleteRefId: %s", remoteCompleteRefId.c_str());
        if (remoteCompleteRefId == completedRefId){
            d->m_remoteInfo.id = remoteRef.second.id;
            d->m_remoteInfo.arch = remoteRef.second.arch;
            d->m_remoteInfo.branch = remoteRef.second.branch;
            d->m_remoteInfo.module = remoteRef.second.kind; // 存在段错误
            d->m_remoteInfo.completedId = remoteCompleteRefId;

            isFound = true;

            break;
        }

    }
#endif
    d->m_remoteInfo.id = commonRef.id;
    d->m_remoteInfo.arch = commonRef.arch;
    d->m_remoteInfo.branch = commonRef.branch;
    d->m_remoteInfo.module = commonRef.baseType;
    remoteCompleteRefId = completedRefId;
    d->m_remoteInfo.completedId = remoteCompleteRefId;
    isFound = true;

    if (!isFound)
    {
        kmlogger.info("find remote ref %s failed", remoteCompleteRefId.c_str());
        printf("find remote ref %s failed", remoteCompleteRefId.c_str());
        return KM_ERROR_FOUND_REMOTE_REF_FAILED;
    }

    // Todo:
    // 2. Get version from software center server
    guint64 installSize;
    int ret = getRemoteInstallSize(installSize);
    kmlogger.info("installSize: %ld", installSize);

    d->m_remoteInfo.size = (double)installSize;
    d->m_remoteInfo.installedSize = formatFileSize((double)d->m_remoteInfo.size);

    printRefRemoteInfo(d->m_remoteInfo);

    return ret;
}

void KMInfoCommand::init()
{
    d->m_options = shared_ptr<Options>(new Options());
    d->m_options = std::make_unique<Options>();

    d->m_folder = std::shared_ptr<KMFolder>(new KMFolder("/opt/kaiming", false));
    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());

    std::string ostreeRepoPath = d->m_folder->getRepoPath().string();
    d->m_ostreeHandler = shared_ptr<KMOSTreeHandler>(new KMOSTreeHandler(ostreeRepoPath));
    d->m_remoteRefs = d->m_ostreeHandler->getRemoteRefs(REPO_NAME);
}

/**
 * @brief 给软件商店调用的api
 *
 * @param name 开明包名，如org.kde.kclock
 * @param version 开明版本号，这里实际上是ostree branch版本，暂未细化到具体子版本。空代表最新版本，如"master"
 * @param error
 * @return true
 * @return false
 */
string KMInfoCommand::getLocalInfo(string name, int &errorCode)
{
    int ret = KM_ERROR_NO;

    ret = start(name);

    errorCode = ret;

    string packInfoToJson;

    if (errorCode != KM_ERROR_NO)
    {
        packInfoToJson = KMJsonHelper::packLocalInfoToJson(d->m_localInfo.id, "", 0, "");
    }
    else
    {
        packInfoToJson = KMJsonHelper::packLocalInfoToJson(d->m_localInfo.id, d->m_localInfo.version, d->m_localInfo.size, d->m_localInfo.branch);
    }

    kmlogger.info("Info packInfoToJson: %s", packInfoToJson.c_str());

    return packInfoToJson;
}

/**
 * @brief 给软件商店调用的api
 *
 * @param name 开明包名，如org.kde.kclock
 * @param version 开明版本号，这里实际上是ostree branch版本，暂未细化到具体子版本。空代表最新版本，如"master"
 * @param error
 * @return true
 * @return false
 */
string KMInfoCommand::getRemoteInfo(string name, int &errorCode)
{
    int ret = KM_ERROR_NO;

    d->isRemoteApi = true;

    ret = start(name);

    errorCode = ret;

    string packRemoteInfoToJson;

    if (errorCode != KM_ERROR_NO)
    {
        packRemoteInfoToJson = KMJsonHelper::packRemoteInfoToJson(d->m_remoteInfo.id, 0, "");
    }
    else
    {
        packRemoteInfoToJson = KMJsonHelper::packRemoteInfoToJson(d->m_remoteInfo.id, d->m_remoteInfo.size, d->m_remoteInfo.branch);
    }

    kmlogger.info("Info packRemoteInfoToJson: %s", packRemoteInfoToJson.c_str());

    return packRemoteInfoToJson;
}

/**
 * @brief 校验refId参数是否合法的接口
 *
 * 校验规则：以"."为分隔符切分字符串refId得到的子串个数小于3个，则代表参数非法，返回false
 *
 * @param refId
 * @return true
 * @return false
 */
bool KMInfoCommand::isValidRefId(const std::string &refId)
{
    if (refId == "")
    {
        return false;
    }

    std::vector<std::string> tokens;
    std::istringstream iss(refId);
    std::string token;
    while (std::getline(iss, token, '.'))
    {
        tokens.push_back(token);
    }

    if (token.size() < 3)
    {
        return false;
    }

    return true;
}

/**
 * @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
 */
KMCommonRef KMInfoCommand::makeRefDataFromRefId(std::string refId, std::string &completeRefId)
{
    KMCommonRef ref;

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

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

    bool onlyAppid = false;

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

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

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

        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];
    ref.arch = tokens[2];
    ref.branch = tokens[3];
    ref.completedId = ref.baseType.append("/").append(ref.id).append("/").append(ref.arch).append("/").append(ref.branch);
    completeRefId = ref.completedId;

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

    return ref;
}

/**
 * @brief 格式化输出下载的包信息，运行时输出是下载大小，软件包是安装大小
 *
 * @param ref
 * @param index
 */
void KMInfoCommand::printRefInfo(KMLocalInfo info)
{
    // printf("\n%s - %s\n\n", info.name.c_str(), info.description.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Name:"), info.name.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Id:"), info.id.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Branch:"), info.branch.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Module:"), info.module.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Version:"), info.version.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Size:"), formatFileSize(info.size).c_str());
    printBoldColorHead(YELLOW_COLOR, _("Description:"), info.description.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Runtime:"), info.runtime.c_str());
    printf("\n");
    if (d->m_localInfo.commitData != nullptr)
    {
        printf("\n");
        printBoldColorHead(YELLOW_COLOR, _("Commit:"), info.commit.c_str());

        if (info.parent != " ")
        {
            printBoldColorHead(YELLOW_COLOR, _("Parent:"), info.parent.c_str());
        }

        if (info.subject != " ")
        {
            printBoldColorHead(YELLOW_COLOR, _("Subject:"), info.subject.c_str());
        }

        if (info.date != "?")
        {
            printBoldColorHead(YELLOW_COLOR, _("Date:"), info.date.c_str());
        }

        // if (info.collection != " ")
        //     printBoldColorHead(YELLOW_COLOR, _("CollectionId:"), info.collection.c_str());
    }
}

/**
 * @brief 格式化输出远程的包信息，运行时输出是下载大小，软件包是安装大小
 *
 * @param ref
 * @param index
 */
void KMInfoCommand::printRefRemoteInfo(KMLocalInfo info)
{
    printf("\n");
    printBoldColorHead(YELLOW_COLOR, _("ID:"), info.id.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Ref:"), info.completedId.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Arch:"), info.arch.c_str());
    printBoldColorHead(YELLOW_COLOR, _("Branch:"), info.branch.c_str());
    printBoldColorHead(YELLOW_COLOR, _("InstalledSize:"), info.installedSize.c_str());
}

/**
 * @brief printf打印时加粗和加颜色
 *
 * @param text 打印文本
 * @param color 颜色选择，31 红色 33 黄色
 */
void KMInfoCommand::printBoldColor(int color, const char *text)
{
    printf("\033[1m\033[%dm%s\033[0m ", color, text);
}

/**
 * @brief 标题printf打印时加粗和加颜色
 *
 * @param text 打印文本
 * @param color 颜色选择，31 红色 33 黄色
 * @return string
 */
void KMInfoCommand::printBoldColorHead(int color, const char *head, const char *text)
{
    printf("\033[1m\033[%dm%s\033[0m %s\n", color, head, text);
}

/**
 * @brief 格式化文件大小
 *
 * @param size
 * @return string
 */
string KMInfoCommand::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 将时间戳转变成友好的时间字符串格式： ""
 *
 * @param timestamp 时间戳
 * @return char* 友好的时间字符串，如 "2024-04-16 18:35:39 +0000"
 */
char *KMInfoCommand::formatTimestamp(guint64 timestamp)
{
    GDateTime *dt;
    char *str;

    dt = g_date_time_new_from_unix_utc(timestamp);
    if (dt == NULL)
    {
        return g_strdup("?");
    }

    str = g_date_time_format(dt, "%Y-%m-%d %H:%M:%S +0000");
    g_date_time_unref(dt);

    return str;
}

/**
 * @brief 获取远程包大小
 *
 * @param installSize 获取的远程包大小
 * @return int 错误码
 */
int KMInfoCommand::getRemoteInstallSize(guint64 &installSize)
{
    string ostreeRepoUrl = d->m_ostreeHandler->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;
    }

    const char *ref;    // "app/org.kde.kclock/x86_64/master";
    VarRefInfoRef info; // 每一个搜索的ref对应的info
    char *checksum = NULL;
    GBytes *metadataBytes = NULL;
    guint64 downloadSize = 0;
    guint64 installedSize = 0;
    const char *metadata = NULL;
    VarMetadataRef sparseCache;
    char *summaryChecksum = NULL;

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

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

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

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

    if (d->m_remoteInfo.module == "app")
    {
        installSize = installedSize;
    }
    else
    {
        installSize = downloadSize;
    }

    kmlogger.info("installSize: %ld installedSize: %ld downloadSize: %ld", installSize, installedSize, downloadSize);

    return KM_ERROR_NO;
}

void KMInfoCommand::findInfoJsonFiles(const fs::path &dirPath, const std::string &targetFilename, const std::string &destDir, const std::string &refId)
{
    KMInfoJson infoJson;
    // 遍历并处理所有的info.json
    try
    {
        for (const auto &dirEntry : fs::directory_iterator(dirPath))
        {
            KMLocalInfo localInfo;
            // 找到所有的 info.json 文件
            if (fs::is_symlink(fs::path(dirEntry)))
            {
                continue;
            }

            if (fs::is_directory(dirEntry))
            {
                // 递归处理子目录
                std::string subSrcDir = dirEntry.path().string();
                std::string subDestDir = destDir + "/" + dirEntry.path().filename().string();
                fs::create_directory(subDestDir);
                // 如果是目录，则递归调用
                findInfoJsonFiles(subSrcDir, targetFilename, subDestDir, refId);
            }
            else if (dirEntry.is_regular_file() && dirEntry.path().filename() == targetFilename)
            {
                fs::path infoJsonPath = dirEntry.path();
                // 调用 loadFile() 函数解析info.json文件
                infoJson.loadFile(infoJsonPath);

                // 使用--kind --arch参数时过滤，只输出匹配的应用
                bool matchArch = d->m_options->m_arch.empty();
                // 获取信息
                if (((infoJson.id == refId) && (matchArch == true)) || ((infoJson.id == refId) && (infoJson.archs.back() == d->m_options->m_arch) && (matchArch == false)))
                {
                    localInfo.id = infoJson.id;
                    localInfo.completedId = infoJson.base;
                    localInfo.runtime = infoJson.runtime;
                    localInfo.module = infoJson.module;
                    localInfo.size = infoJson.size;
                    localInfo.version = infoJson.version;
                    localInfo.name = infoJson.name;
                    localInfo.branch = infoJson.channel;
                }
                else
                {
                    continue;
                }
                
                // 获取当前语言环境
                KMUtil locale;
                std::string localeName = locale.getCurrentLocale();
                if (!infoJson.names["name[" + localeName + "]"].empty())
                {
                    localInfo.name = infoJson.names["name[" + localeName + "]"];
                }
                else
                {
                    localInfo.name = infoJson.name;
                }

                if (!infoJson.descriptions["description[" + localeName + "]"].empty())
                {
                    localInfo.description = infoJson.descriptions["description[" + localeName + "]"];
                }
                else
                {
                    localInfo.description = infoJson.description;
                }

                printRefInfo(localInfo);
            }
        }
    }
    catch (const fs::filesystem_error &e)
    {
        // 输出错误信息并跳过此目录
        kmlogger.error("Skipping directory due to access error.");
    }
}