#include "KMRunner.h"

#include <fmt/format.h>
#include <unistd.h>
#include <unordered_set>
#include <sys/mount.h>
#include <pwd.h>
#include <grp.h>

#include "KMReference.h"
#include "KMRunnerOptions.h"
#include "common/KMConfigData.h"
#include "common/KMContainer.h"
#include "common/KMLogger.h"
#include "common/KMUtil.h"

REGISTER_SUBCOMMAND_DYNCREATE(run, KMRunner)

class KMRunner::Private
{
public:
    std::string appId;
    std::string appDir;
    std::string baseDir;
    std::string runtimeDir;
    std::string appDataPath;
    std::string optionCommand;
    std::vector<std::string> commandArgs;
    std::vector<std::string> infoCommands;
    std::map<std::string, std::string> infoEnvs;
    std::unique_ptr<KMContainer> container;
    std::unique_ptr<KMRunnerOptions> options;
};

/**
 * @brief 构造函数
 */
KMRunner::KMRunner()
    : d_ptr(std::make_shared<KMRunner::Private>())
{
    d_ptr->container = std::make_unique<KMContainer>();
    d_ptr->options = std::make_unique<KMRunnerOptions>();
}

/**
 * @brief 开明子命令运行
 * @param argc 参数个数
 * @param argv 参数列表
 * @return 0 成功 非0 失败
 */
int KMRunner::despose(int argc, char **argv)
{
    if (!parseArgs(argc, argv))
    {
        return false;
    }

    return start() ? EXIT_SUCCESS : -1;
}

/**
 * @brief 解析命令行参数
 * @param argc 参数个数
 * @param argv 参数列表
 * @return true 成功 false 失败
 */
bool KMRunner::parseArgs(int argc, char **argv)
{
    // 参数解析
    d_ptr->options->parseCommandLine(argc, argv);

    d_ptr->appId = d_ptr->options->getAppId();
    if (d_ptr->appId.empty())
    {
        KMError("app id is empty");
        return false;
    }

    d_ptr->optionCommand = d_ptr->options->getCommand();

    // 不使用options解析的命令行参数,因为options后续的解析包含-开头的参数
    // d_ptr->commandArgs = d_ptr->options->getArgs();
    int index = 0;
    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] != '-' && index == 0)
        {
            index = i + 1;
            continue;
        }

        if (index == 0)
        {
            continue;
        }

        if (!d_ptr->options->isFileWarding())
        {
            d_ptr->commandArgs.emplace_back(argv[i]);
            continue;
        }

        if (string(argv[i]) == string("@@") || string(argv[i]) == string("@@u"))
        {
            continue;
        }

        d_ptr->commandArgs.emplace_back(argv[i]);
    }

    kmlogger.info("start app %s", d_ptr->appId);

    return true;
}

/**
 * @brief 开始运行
 * @return true 成功 false 失败
 */
bool KMRunner::start()
{
    if (runningUnderSudo())
    {
        KMError("run under sudo is not allowed");
        return false;
    }

    if (!getLayersDirs())
    {
        KMError("get layers dirs failed");
        return false;
    }

    if (!ensureAppDataDir())
    {
        KMError("create app data directory failed ");
        return false;
    }

    if (!mountLayers())
    {
        KMError("mount layers failed");
        return false;
    }

    if (!mountBase())
    {
        KMError("mount others failed");
        return false;
    }

    if (!mountData())
    {
        KMError("mount data failed");
        return false;
    }

    if (!mountDev())
    {
        KMError("mount dev failed");
        return false;
    }

    if (!mountSocket())
    {
        KMError("mount socket failed");
        return false;
    }

    if (!mountShare())
    {
        KMError("mount share failed");
        return false;
    }

    if (!genLdsocache())
    {
        KMError("mount ldsocache failed");
        return false;
    }

    if (!setProcessCmd())
    {
        KMError("set process failed");
        return false;
    }

    if (!d_ptr->container->run())
    {
        KMError("run container failed");
        return false;
    }

    return true;
}

/**
 * @brief 是否在root权限下运行
 * @return true 成功 false 失败
 */
bool KMRunner::runningUnderSudo()
{
    const char *sudoCommandEnv = getenv("SUDO_COMMAND");
    if (!sudoCommandEnv)
        return false;

    return true;
}

/**
 * @brief 获取app,base,runtime目录
 * @return true 成功 false 失败
 */
bool KMRunner::getLayersDirs()
{
    KMReference ref;
    if (!ref.getLayerDir(d_ptr->appId, d_ptr->options->isDevel()))
    {
        KMError("get layer dir failed");
        return false;
    }

    if (!ref.getAppDir(d_ptr->appDir))
    {
        KMError("get app dir failed");
        return false;
    }

    if (!ref.getBaseDir(d_ptr->baseDir))
    {
        KMError("get base dir failed");
        return false;
    }

    if (!ref.getRuntimeDir(d_ptr->runtimeDir))
    {
        KMError("get runtime dir failed");
        return false;
    }

    if (!ref.getCommands(d_ptr->infoCommands))
    {
        KMError("get commands failed");
        return false;
    }

    if (!ref.getEnvs(d_ptr->infoEnvs))
    {
        KMError("get envs failed");
        return false;
    }

    kmlogger.info("app dir [%s], base dir: [%s], runtime dir: [%s]", d_ptr->appDir, d_ptr->baseDir, d_ptr->runtimeDir);
    return true;
}

/**
 * @brief 创建appdate子目录
 * @return true 成功 false 失败
 */
bool KMRunner::ensureAppDataDir()
{
    std::error_code ec;
    d_ptr->appDataPath = KMFolder::getAppDataPath(d_ptr->appId);

    fs::path appDataPath(d_ptr->appDataPath);

    if (!fs::exists(appDataPath) && !fs::create_directories(appDataPath, ec))
        return false;

    if (!fs::exists(appDataPath / ".hostcache") && !fs::create_directories(appDataPath / ".hostcache", ec))
        return false;

    if (!fs::exists(appDataPath / "upperdir") && !fs::create_directories(appDataPath / "upperdir", ec))
        return false;

    if (!fs::exists(appDataPath / "workdir") && !fs::create_directories(appDataPath / "workdir", ec))
        return false;

    return true;
}

/**
 * @brief 挂载app,base,runtime目录
 * @return true 成功 false 失败
 */
bool KMRunner::mountLayers()
{
    d_ptr->container->setAppID(d_ptr->appId);
    d_ptr->container->setBaseDir(d_ptr->baseDir);
    d_ptr->container->addAnnotation("kaiming.app.id", d_ptr->appId);
    d_ptr->container->addAnnotation("kaiming.app.dir", d_ptr->appDir);
    d_ptr->container->addAnnotation("kaiming.base.dir", d_ptr->baseDir);
    d_ptr->container->addAnnotation("kaiming.runtime.dir", d_ptr->runtimeDir);

    std::string upperdir = d_ptr->appDataPath + "/upperdir";
    std::string workDir = string("workdir=") + string(d_ptr->appDataPath + "/workdir");

    // mount overlayfs
    for (auto &entry : fs::directory_iterator(d_ptr->baseDir + "/files"))
    {
        std::string upperDir, dst;
        std::string src = string("overlay");
        std::string type = string("overlay");
        std::vector<std::string> options;

        if (!entry.is_directory())
        {
            continue;
        }

        // 生成upperdir目录
        string lowerdir = "lowerdir=";
        dst = string("/") + entry.path().filename().string();
        if (!fs::exists(upperdir + dst))
        {
            std::error_code ec;
            fs::create_directories(upperdir + dst, ec);
            generateUpperLayers(entry.path().string());
        }
        upperDir.append("upperdir=").append(upperdir + dst);

        // 基于overlay处理base,runtime,app目录
        if (fs::exists(d_ptr->appDir + string("/files") + dst))
        {
            lowerdir.append(d_ptr->appDir + "/files" + dst + string(":"));
        }
        if (fs::exists(d_ptr->runtimeDir + string("/files") + dst))
        {
            lowerdir.append(d_ptr->runtimeDir + "/files" + dst + string(":"));
        }
        if (fs::exists(d_ptr->baseDir + string("/files") + dst))
        {
            lowerdir.append(d_ptr->baseDir + "/files" + dst);
        }

        options = { lowerdir, upperDir, workDir };
        d_ptr->container->addMount(Mount{ src, dst, type, options });
    }

    return true;
}

/**
 * @brief 生成upperdir的n层目录,默认3层
 * @param path 目录路径
 * @param depth 目录深度
 * @return true 成功 false 失败
 */
bool KMRunner::generateUpperLayers(const std::string &root, int depth)
{
    std::string upperdir = d_ptr->appDataPath + "/upperdir";
    if (depth < 1)
    {
        return true;
    }

    // 不具备访问权限的目录略过，不需要创建对应upperdir目录
    if (access(root.c_str(), R_OK) != 0)
    {
        return true;
    }

    for (const auto &entry : fs::directory_iterator(root))
    {
        if (entry.is_directory())
        {
            std::error_code ec;
            string subSrc = entry.path().string().substr(string(d_ptr->baseDir + "/files").length());
            std::string subDst = upperdir + subSrc;
            fs::create_directories(subDst, ec);
            generateUpperLayers(entry.path().string(), depth - 1);
        }
    }

    return true;
}

/**
 * @brief 设置process
 * @return true 成功 false 失败
 */
bool KMRunner::setProcessCmd()
{
    if (!assembleCommand())
    {
        KMError("assemble command failed");
        return false;
    }

    if (!assembleProcEnv())
    {
        KMError("assemble process env failed");
        return false;
    }

    return true;
}

/**
 * @brief 组装运行命令
 * @return true 成功 false 失败
 */
bool KMRunner::assembleCommand()
{
    // 优先级: 命令行参数option > info.json, 二选一
    std::string command;
    if (!d_ptr->optionCommand.empty())
    {
        command.append(d_ptr->optionCommand);
        for (auto &arg : d_ptr->commandArgs)
        {
            command.append(" ").append(arg);
        }
    }
    else
    {
        for (auto &arg : d_ptr->infoCommands)
        {
            command.append(" ").append(arg);
        }
    }
    if (command.empty())
    {
        KMError("command is empty");
        return false;
    }

    std::vector<string> args = { "/bin/bash", "--login", "-e", "-c" };
    args.emplace_back(command);
    args.emplace_back("; wait");
    d_ptr->container->setProcessArgs(args);

    return true;
}

/**
 * @brief 组装运行环境变量
 * @return true 成功 false 失败
 */
bool KMRunner::assembleProcEnv()
{
    Process process = d_ptr->container->getProcess();
    // 获取系统环境变量
    std::map<std::string, std::string> envs;
    for (auto &env : process.env)
    {
        auto key = env.substr(0, env.find_first_of('='));
        auto value = env.substr(env.find_first_of('=') + 1);
        envs[key] = value;
    }

    // 设置开明需要的环境变量
    std::map<std::string, std::string> newEnvs;
    auto sessionAddress = getenv("DBUS_SESSION_BUS_ADDRESS");
    string session = (sessionAddress == nullptr) ? string("unix:path=") + string("/run/user/") + to_string(getuid()) + string("/bus") : string(sessionAddress);
    newEnvs["DBUS_SESSION_BUS_ADDRESS"] = session;

    auto sysAddress = getenv("DBUS_SYSTEM_BUS_ADDRESS");
    if (sysAddress != nullptr)
    {
        newEnvs["DBUS_SYSTEM_BUS_ADDRESS"] = string(sysAddress);
    }
    else if (fs::exists(string("/run/dbus/system_bus_socket")))
    {
        newEnvs["DBUS_SYSTEM_BUS_ADDRESS"] = string("unix:path=/run/dbus/system_bus_socket");
    }

    auto *home = getenv("HOME");
    if (home == nullptr)
    {
        KMError("Couldn't get HOME from env ");
        return false;
    }
    string homeDir = string(home);

    string xauthFile;
    auto pXauthFile = getenv("XAUTHORITY");
    if (pXauthFile != nullptr && std::filesystem::exists(pXauthFile))
    {
        xauthFile = string(pXauthFile);
    }
    else
    {
        xauthFile = homeDir + string("/.Xauthority");
    }
    newEnvs["XAUTHORITY"] = xauthFile;
    newEnvs["XDG_RUNTIME_DIR"] = string("/run/user/") + to_string(getuid());
    auto pXdgDataHome = getenv("XDG_DATA_HOME");
    std::string XDGDataHome = pXdgDataHome == nullptr ? (homeDir + string("/.local/share")) : string(pXdgDataHome);
    newEnvs["XDG_DATA_HOME"] = XDGDataHome;
    newEnvs["XDG_CONFIG_HOME"] = homeDir + string("/.config");
    newEnvs["XDG_CACHE_HOME"] = homeDir + string("/.cache");
    newEnvs["XDG_STATE_HOME"] = homeDir + string("/.local/state");

    auto path = getenv("PATH");
    if (path != nullptr)
    {
        newEnvs["PATH"] = string(path);
    }
    else
    {
        newEnvs["PATH"] = string("/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin:/usr/local/sbin");
    }

    // 主要编包环境变量
    newEnvs["KAIMING_ID"] = d_ptr->appId;

    // 兼容玲珑,玲珑包无此环境变量无法找到对应的程序
    newEnvs["LINGLONG_APPID"] = d_ptr->appId;

    // 增加QT相关环境变量
    newEnvs["QML2_IMPORT_PATH"] = string("/lib64/qml:") + string("/lib/qml");
    newEnvs["QT_PLUGIN_PATH"] = string("/lib64/plugins:") + string("/lib/plugins:") + string("/lib/x86_64-linux-gnu/qt5/plugins/");
    newEnvs["__EGL_EXTERNAL_PLATFORM_CONFIG_DIRS"] = string("/etc/egl/egl_external_platform.d:"
                                                            "/usr/lib/x86_64-linux-gnu/GL/egl/egl_external_platform.d:"
                                                            "/usr/share/egl/egl_external_platform.d");

    // 增加XDG相关环境变量
    newEnvs["XDG_CONFIG_DIRS"] = string("/etc/xdg/xdg-ukui:/etc/xdg");
    newEnvs["XDG_DATA_DIRS"] = string("/usr/share:/usr/local/share:/usr/share/ukui:/share");

    // 增加app应用中的环境变量
    std::map<std::string, std::string> infoEnvs = d_ptr->infoEnvs;

    // 合并处理环境变量
    KMReference ref;
    ref.appendEnvs(envs, newEnvs);
    ref.appendEnvs(envs, infoEnvs);

    // 处理环境变量中的变量引用
    for (auto &[k, v] : envs)
    {
        auto it = v.find(string("$") + k);
        if (it != string::npos)
        {
            if (v.find(string("$") + k + string(":")) != string::npos)
            {
                v.replace(it, k.length() + 2, "");
            }
            else
            {
                v.replace(it, k.length() + 1, "");
            }
        }
    }

    std::vector<string> dedupEnvs;
    for (auto &[k, v] : envs)
    {
        dedupEnvs.emplace_back(k + "=" + v);
    }

    d_ptr->container->setProcessEnv(dedupEnvs);

    return true;
}

/**
 * @brief 生成ldso缓存
 * @return true 成功 false 失败
 */
bool KMRunner::genLdsocache()
{
    std::vector<Hook> start = std::vector<Hook>{ Hook{ "/bin/bash", std::vector<std::string>{ "/bin/bash", "-c", "/sbin/ldconfig" } } };
    d_ptr->container->setStartContainer(start);

    return true;
}

/**
 * @brief 挂载基础目录
 * @return true 成功 false 失败
 */
bool KMRunner::mountBase()
{
    string dst, src, type;
    std::vector<std::string> options;

    dst = string("/proc");
    src = string("proc");
    type = string("proc");
    d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type });

    dst = string("/tmp");
    src = string("tmpfs");
    type = string("tmpfs");
    options = { "nodev", "nosuid", "noexec" };
    d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type, .options = options });

    dst = string("/sys");
    src = string("tmpfs");
    type = string("tmpfs");
    options = { "nodev", "nosuid", "noexec" };
    d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type, .options = options });

    dst = string("/sys");
    src = string("/sys");
    type = string("bind");
    options = { "rbind", "ro" };
    if (fs::exists(src))
    {
        d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type, .options = options });
    }

    dst = string("/proc/self/ns/user");
    src = string("/run/.userns");
    if (fs::exists(src))
    {
        d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type, .options = options });
    }

    dst = string("/etc/timezone");
    src = string("/var/db/zoneinfo");
    if (fs::exists(src))
    {
        d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type, .options = options });
    }

    dst = string("/run/host/rootfs");
    src = string("/");
    type = string("bind");
    options = { "rbind", "ro" };
    if (fs::exists(src))
    {
        d_ptr->container->addMount(Mount{ .source = src, .destination = dst, .type = type, .options = options });
    }

    auto *home = getenv("HOME");
    if (home == nullptr)
    {
        KMError("Couldn't get HOME from env ");
        return false;
    }
    if (fs::exists(string(home)))
    {
        type = string("bind");
        options = { "rbind" };
        d_ptr->container->addMount(Mount{ .source = string(home), .destination = string(home), .type = type, .options = options });

        // TODO:后续确认哪些目录是可修改的,可修改指的修改宿主机文件
        // std::string workDir = string("workdir=") + string(d_ptr->appDataPath + "/workdir");
        // std::string upperDir = d_ptr->appDataPath + "/upperdir" + string(home);
        // if (!fs::exists(upperDir))
        // {
        //     fs::create_directories(upperDir);
        // }
        // string lowerDir = string("lowerdir=") + string(home);
        // upperDir.insert(0, "upperdir=");
        // options = { lowerDir, upperDir, workDir };
        // d_ptr->container->addMount(Mount{ .source = string("overlay"), .destination = string(home), .type = string("overlay"), .options = options });
    }

    // 挂载 /run/user/1000
    if (fs::exists(string("/run/user/") + std::to_string(getuid())))
    {
        string dir = string("/run/user/") + to_string(getuid());
        d_ptr->container->addMount(Mount{ .source = dir, .destination = dir, .type = "bind", .options = { { "rbind" } } });
    }

    if (fs::exists("/lost+found"))
    {
        d_ptr->container->addMount(Mount{ .source = "/lost+found", .destination = "/lost+found", .type = "bind", .options = { { "rbind" } } });
    }

    if (fs::exists("/backup"))
    {
        d_ptr->container->addMount(Mount{ .source = "/backup", .destination = "/backup", .type = "bind", .options = { { "rbind" } } });
    }

    if (fs::exists("/data"))
    {
        d_ptr->container->addMount(Mount{ .source = "/data", .destination = "/data", .type = "bind", .options = { { "rbind" } } });
    }

    if (fs::exists("/cdrom"))
    {
        d_ptr->container->addMount(Mount{ .source = "/cdrom", .destination = "/cdrom", .type = "bind", .options = { { "rbind" } } });
    }

    return true;
}

/**
 * @brief 挂载dev设备
 * @return true 成功 false 失败
 */
bool KMRunner::mountDev()
{
    std::string src, dst, type;
    std::vector<std::string> options;
    dst = string("/dev");
    src = string("/dev");
    type = string("bind");
    options = { "rbind" };
    d_ptr->container->addMount(Mount{ src, dst, type, options });

    std::vector<string> devDefault = { "/run/udev", "/dev/dri", "/dev/disk", "/dev/shm", "/dev/kvm", "/dev/mali", "/dev/mali0", "/dev/umplock",
                                       /* nvidia */
                                       "/dev/nvidiactl", "/dev/nvidia-modeset",
                                       /* nvidia OpenCL/CUDA */
                                       "/dev/nvidia-uvm", "/dev/nvidia-uvm-tools" };
    for (const auto &dev : devDefault)
    {
        if (!fs::exists(dev))
            continue;

        d_ptr->container->addMount(Mount{ .source = dev, .destination = dev, .type = "bind", .options = { { "rbind" } } });
    }

    if (!mountPulseaudio())
    {
        KMError("mount pulseaudio failed");
        return false;
    }

    return true;
}

/**
 * @brief 挂载socket
 * @return true 成功 false 失败
 */
bool KMRunner::mountSocket()
{
    if (!mountX11())
    {
        KMError("mount x11 failed");
        return false;
    }

    if (!mountWayland())
    {
        KMError("mount wayland failed");
        return false;
    }

    mountGssproxy();
    mountResolved();
    mountJournal();

    if (!mountDbus())
    {
        KMError("mount dbus failed");
        return false;
    }

    return true;
}

/**
 * @brief 挂载share,包含字体,icon等
 * @return true 成功 false 失败
 */
bool KMRunner::mountShare()
{
    // 挂载主题配置
    std::string sysThemesPath{ "/usr/share/themes" };
    if (fs::exists(sysThemesPath))
    {
        d_ptr->container->addMount(Mount{ .source = sysThemesPath, .destination = sysThemesPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    std::string etcFontsPath{ "/etc/fonts" };
    if (fs::exists(etcFontsPath))
    {
        d_ptr->container->addMount(Mount{ .source = etcFontsPath, .destination = etcFontsPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    std::string sysFontsPath{ "/usr/share/fonts" };
    if (fs::exists(sysFontsPath))
    {
        d_ptr->container->addMount(Mount{ .source = sysFontsPath, .destination = sysFontsPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    std::string etcFontsPath1{ "/usr/share/fontconfig" };
    if (fs::exists(etcFontsPath1))
    {
        d_ptr->container->addMount(Mount{ .source = etcFontsPath1, .destination = "/usr/share/fontconfig", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    // 挂载本地字体
    std::string localFontsPath{ "/usr/local/share/fonts" };
    if (fs::exists(localFontsPath))
    {
        d_ptr->container->addMount(Mount{ .source = localFontsPath, .destination = localFontsPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    std::string cacheFontsConfig{ "/var/cache/fontconfig:/usr/lib/fontconfig/cache" };
    for (auto config : KMUtil::split(cacheFontsConfig, ':'))
    {
        if (fs::exists(config))
        {
            d_ptr->container->addMount(Mount{ .source = config, .destination = config, .type = "bind", .options = { { "rbind", "ro" } } });
            break;
        }
    }

    std::string userFontPath = KMFolder::getUserDataPath() / "fonts";
    std::string homeFontPath = KMFolder::getHomePath() / ".fonts";
    if (fs::exists(userFontPath))
    {
        d_ptr->container->addMount(Mount{ .source = userFontPath, .destination = userFontPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }
    else if (fs::exists(homeFontPath))
    {
        d_ptr->container->addMount(Mount{ .source = homeFontPath, .destination = homeFontPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    std::string useFontCachePath = KMFolder::getUserCachePath() / "fontconfig";
    if (fs::exists(useFontCachePath))
    {
        d_ptr->container->addMount(Mount{ .source = useFontCachePath, .destination = useFontCachePath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    // 挂载icon
    std::string sysIconPath = string{ "/usr/share/icons" };
    if (fs::exists(sysIconPath))
    {
        d_ptr->container->addMount(Mount{ .source = sysIconPath, .destination = sysIconPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    std::string userIconPath = string{ KMFolder::getUserDataPath() / "icons" };
    if (fs::exists(userIconPath))
    {
        d_ptr->container->addMount(Mount{ .source = userIconPath, .destination = userIconPath, .type = "bind", .options = { { "rbind", "ro" } } });
    }

    return true;
}

/**
 * @brief 挂载GSSProxy配置
 */
void KMRunner::mountGssproxy()
{
    string gssproxy = KMFolder::getXdgRuntimePath() / "gssproxy";
    if (fs::exists(gssproxy))
    {
        d_ptr->container->addMount(Mount{ .source = gssproxy, .destination = gssproxy, .type = "bind", .options = { { "rbind", "ro" } } });
    }
}

/**
 * @brief 挂载resolved配置
 */
void KMRunner::mountResolved()
{
    string resolved = string("/run/systemd/resolve/io.systemd.Resolve");
    if (fs::exists(resolved))
    {
        d_ptr->container->addMount(Mount{ .source = resolved, .destination = resolved, .type = "bind", .options = { { "rbind", "ro" } } });
    }
}

/**
 * @brief 挂载journal配置
 */
void KMRunner::mountJournal()
{
    string journalSocket = string("/run/systemd/journal/socket");
    string journalStdout = string("/run/systemd/journal/stdout");
    if (fs::exists(journalSocket))
    {
        d_ptr->container->addMount(Mount{ .source = journalSocket, .destination = journalSocket, .type = "bind", .options = { { "rbind", "ro" } } });
    }
    if (fs::exists(journalStdout))
    {
        d_ptr->container->addMount(Mount{ .source = journalStdout, .destination = journalStdout, .type = "bind", .options = { { "rbind", "ro" } } });
    }
}

/**
 * @brief 挂载pulseaudio配置
 * @return true 成功 false 失败
 */
bool KMRunner::mountPulseaudio()
{
    std::string pulseSocket = KMFolder::getPulseRuntimePath() / "native";
    if (!fs::exists(pulseSocket))
    {
        if (fs::exists(string("/var/run/pulse/native")))
        {
            pulseSocket = string("/var/run/pulse/native");
        }
        else
        {
            pulseSocket = string("");
        }
    }

    if (!pulseSocket.empty())
    {
        string configPath = KMFolder::getPulseRuntimePath() / "config";
        string hostConfigPath = d_ptr->appDataPath + "/.hostcache/config";

        ofstream ofs(hostConfigPath, std::ios::out | std::ios::trunc);
        if (!ofs.is_open())
        {
            ofs.close();
            KMError("create pulse config file failed");
            return false;
        }

        ofs << string("enable-shm=no") << std::endl;
        ofs.close();

        // 设置挂载
        d_ptr->container->addMount(Mount{ .source = pulseSocket, .destination = pulseSocket, .type = "bind", .options = { { "rbind" } } });
        d_ptr->container->addMount(Mount{ .source = hostConfigPath, .destination = configPath, .type = "bind", .options = { { "rbind", "ro" } } });

        // 设置环境变量
        Process process = d_ptr->container->getProcess();
        process.env.emplace_back(string("PULSE_SERVER=") + pulseSocket);
        process.env.emplace_back(string("PULSE_CLIENTCONFIG=") + configPath);
        d_ptr->container->setProcess(process);
    }

    if (fs::exists(string("/dev/snd")))
    {
        d_ptr->container->addMount(Mount{ .source = "/dev/snd", .destination = "/dev/snd", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    return true;
}

/**
 * @brief 挂载dbus配置
 * @return true 成功 false 失败
 */
bool KMRunner::mountDbus()
{
    auto *systemBusEnv = getenv("DBUS_SYSTEM_BUS_ADDRESS");
    std::string systemBus = "/var/run/dbus/system_bus_socket";
    if (systemBusEnv != nullptr && std::filesystem::exists(systemBusEnv))
    {
        systemBus = systemBusEnv;
    }

    if (!std::filesystem::exists(systemBus))
    {
        KMError("dbus system bus socket not found at " + systemBus);
        return false;
    }
    d_ptr->container->addMount(Mount{ .source = systemBus, .destination = "/run/dbus/system_bus_socket", .type = "bind", .options = { { "rbind", "ro" } } });

    // 挂载user session dbus
    auto sessionAddress = getenv("DBUS_SESSION_BUS_ADDRESS");
    if (sessionAddress == nullptr)
    {
        KMError("dbus session bus address not found");
        return false;
    }
    std::string sessionPath = pathFromAddress(string(sessionAddress));
    if (sessionPath.empty() || !fs::exists(sessionPath))
    {
        KMError(string("dbus session bus path: ") + sessionPath + string(" not found"));
        return false;
    }
    d_ptr->container->addMount(Mount{ .source = sessionPath, .destination = sessionPath, .type = "bind", .options = { { "rbind", "ro" } } });

    return true;
}

/**
 * @brief : 挂载x11
 * @return true 成功 false 失败
 */
bool KMRunner::mountX11()
{
    auto display = getenv("DISPLAY");
    if (display == nullptr)
    {
        KMError("DISPLAY not set");
        return false;
    }

    string x11Socket = "/tmp/.X11-unix";
    if (fs::exists(x11Socket))
    {
        d_ptr->container->addMount(Mount{ .source = x11Socket, .destination = x11Socket, .type = "bind", .options = { { "rbind" } } });
    }

    return true;
}

/**
 * @brief 挂载wayland
 * @return true 成功 false 失败
 */
bool KMRunner::mountWayland()
{
    auto display = getenv("WAYLAND_DISPLAY");
    if (display == nullptr)
    {
        return true;
    }

    string waylandDisplay = string(display);
    string waylandSocker;
    if (waylandDisplay.at(0) == '/')
    {
        waylandSocker = waylandDisplay;
    }
    else
    {
        waylandSocker = KMFolder::getXdgRuntimePath() / waylandDisplay;
    }

    d_ptr->container->addMount(Mount{ .source = waylandSocker, .destination = waylandSocker, .type = "bind", .options = { { "rbind", "ro" } } });

    return true;
}

/**
 * @brief 挂载数据配置
 * @return true 成功 false 失败
 */
bool KMRunner::mountData()
{
    if (!mountEtc())
    {
        KMError("mount etc failed");
        return false;
    }

    if (!mountDconf())
    {
        KMError("mount dconf failed");
        return false;
    }

    return true;
}

/**
 * @brief 挂载dconf目录
 * @return true 成功 false 失败
 */
bool KMRunner::mountDconf()
{
    // 挂载 dconf
    auto *home = getenv("HOME");
    if (home == nullptr)
    {
        KMError("Couldn't get HOME from env ");
        return false;
    }
    if (fs::exists(string(home) + "/.config/dconf/user"))
    {
        std::string dconf = string(home) + string("/.config/dconf/user");
        d_ptr->container->addMount(Mount{ .source = dconf, .destination = dconf, .type = "bind", .options = { { "rbind" } } });
        string userDirs = string(home) + string("/.config/user-dirs.dirs");
        if (fs::exists(userDirs))
        {
            d_ptr->container->addMount(Mount{ .source = userDirs, .destination = userDirs, .type = "bind", .options = { { "rbind" } } });
        }

        string userDirsLocale = string(home) + string("/.config/user-dirs.locale");
        if (fs::exists(userDirsLocale))
        {
            d_ptr->container->addMount(Mount{ .source = userDirsLocale, .destination = userDirsLocale, .type = "bind", .options = { { "rbind" } } });
        }
    }

    return true;
}

/**
 * @brief 挂载etc目录
 * @return true 成功 false 失败
 */
bool KMRunner::mountEtc()
{
    if (fs::exists(string("/etc/passwd")))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/passwd", .destination = "/etc/passwd", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (fs::exists(string("/etc/group")))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/group", .destination = "/etc/group", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (!fs::exists(d_ptr->baseDir + string("/files/pkcs11/pkcs11.conf")))
    {
        std::ofstream ofs(d_ptr->appDataPath + string("/.hostcache") + string("/pkcs11.conf"), std::ios::out | std::ios::trunc);
        if (!ofs.is_open())
        {
            ofs.close();
            KMError("create pkcs11.conf file failed");
            return false;
        }

        ofs << string("# Disable user pkcs11 config, because the host modules don't work in the runtime\n") << std::endl;
        ofs << string("user-config: none") << std::endl;
        ofs.close();

        d_ptr->container->addMount(Mount{ .source = d_ptr->appDataPath + string("/.hostcache") + "/pkcs11.conf", .destination = "/etc/pkcs11/pkcs11.conf", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (fs::exists("/etc/machine-id"))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/machine-id", .destination = "/etc/machine-id", .type = "bind", .options = { { "rbind", "ro" } } });
    }
    else if (fs::exists("/var/lib/dbus/machine-id"))
    {
        d_ptr->container->addMount(Mount{ .source = "/var/lib/dbus/machine-id", .destination = "/var/lib/dbus/machine-id", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (fs::exists("/etc/resolv.conf"))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/resolv.conf", .destination = "/etc/resolv.conf", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (fs::exists("/etc/host.conf"))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/host.conf", .destination = "/etc/host.conf", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (fs::exists("/etc/hosts"))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/hosts", .destination = "/etc/hosts", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    if (fs::exists("/etc/gai.conf"))
    {
        d_ptr->container->addMount(Mount{ .source = "/etc/gai.conf", .destination = "/etc/gai.conf", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    // 设置系统时间挂载参数，如果系统的存在用系统的，系统的不存在，用 runtime/files 下的
    string rawTimeZone = KMUtil::kmGetTimeZone();
    string localtimeZone = string("/usr/share/zoneinfo/") + rawTimeZone;
    string runtimeTimezone = d_ptr->baseDir + string("/files/usr/share/zoneinfo");

    if (fs::exists(runtimeTimezone))
    {
        if (fs::exists("/usr/share/zoneinfo"))
        {
            d_ptr->container->addMount(Mount{ .source = "/usr/share/zoneinfo", .destination = "/usr/share/zoneinfo", .type = "bind", .options = { { "rbind", "ro" } } });
            d_ptr->container->addMount(Mount{ .source = localtimeZone, .destination = "/etc/localtime", .type = "bind", .options = { { "rbind", "ro" } } });
        }
        else if (fs::exists(runtimeTimezone + string("/") + rawTimeZone))
        {
            d_ptr->container->addMount(Mount{ .source = localtimeZone, .destination = "/etc/localtime", .type = "bind", .options = { { "rbind", "ro" } } });
        }
    }

    // 挂载/etc/timezone
    {
        std::ofstream ofs(d_ptr->appDataPath + string("/.hostcache") + "/timezone", std::ios::out | std::ios::trunc);
        if (!ofs.is_open())
        {
            ofs.close();
            KMError("create timezone file failed");
            return false;
        }

        ofs << rawTimeZone << std::endl;
        ofs.close();
        d_ptr->container->addMount(Mount{ .source = d_ptr->appDataPath + string("/.hostcache") + "/timezone", .destination = "/etc/timezone", .type = "bind", .options = { { "rbind", "ro" } } });
    }

    return true;
}

/**
 *@brief 解析dbus地址
 *@return string 路径
 */
string KMRunner::pathFromAddress(const string &address)
{
    if (address.empty())
        return string();

    if (address.find("unix:") == string::npos)
        return string();

    if (address.find("path=") == string::npos)
        return string();

    std::string path = address.substr(address.find("path=") + strlen("path="), address.length() - address.find("path="));
    if (path.empty())
        return string();

    if (path.find(",") != string::npos)
        path = path.substr(0, path.find(","));

    return path;
}
