/*
 * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
 *               2014  Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#include "sessionmanagercontext.h"
#include "sessiondbusadaptor.h"
#include "../tools/lockchecker.h"
#include <QMessageBox>
#include <QPushButton>
#include <QDBusMetaType>
#include <QDBusAbstractAdaptor>
#include <QDebug>

#define WLCOM_SERVICE_BUSNAME "com.kylin.Wlcom"
#define WLCOM_SERVICE_PATH "/com/kylin/Wlcom/View"
#define WLCOM_SERVICE_INTERFACE "com.kylin.Wlcom.View"

SessionManagerDBusContext::SessionManagerDBusContext(ModuleManager *manager, QObject *parent)
    : QObject(parent)
    , mManager(manager)
    , minhibit(new usminhibit())
    , m_systemdProvider(new SystemdProvider())
    , m_ukuiProvider(new UKUIProvider())
    , m_serviceWatcher(new QDBusServiceWatcher(this))
{
    new SessionDBusAdaptor(this);

    connect(mManager, &ModuleManager::moduleStateChanged, this, &SessionManagerDBusContext::moduleStateChanged);
    connect(mManager, &ModuleManager::finished, this, &SessionManagerDBusContext::emitPrepareForPhase2);
    connect(minhibit, &usminhibit::inhibitRemove, this, &SessionManagerDBusContext::simulateUserActivity);
    connect(minhibit, &usminhibit::inhibitAdd, this, &SessionManagerDBusContext::simulateUserActivity);

    m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
    m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
    connect(
        m_serviceWatcher,
        &QDBusServiceWatcher::serviceUnregistered,
        this,
        &SessionManagerDBusContext::on_serviceUnregistered);

    // 注册类型
    qDBusRegisterMetaType<InhibitInfo::InhibitorInfo>();
    qDBusRegisterMetaType<QVector<InhibitInfo::InhibitorInfo>>();
    qDBusRegisterMetaType<SystemdInhibitor::Inhibitor>();
}

SessionManagerDBusContext::~SessionManagerDBusContext() {}

Q_NOREPLY void SessionManagerDBusContext::startupfinished(const QString &appName, const QString &string)
{
    return mManager->startupfinished(appName, string);
}

bool SessionManagerDBusContext::canSwitch()
{
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::switchuserBtn)
        && m_systemdProvider->canAction(UkuiPower::PowerSwitchUser)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

bool SessionManagerDBusContext::canLockscreen()
{
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::lockscreenBtn)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

bool SessionManagerDBusContext::canHibernate()
{
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::hibernateBtn)
        && m_systemdProvider->canAction(UkuiPower::PowerHibernate)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

bool SessionManagerDBusContext::canSuspend()
{
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::suspendBtn)
        && m_systemdProvider->canAction(UkuiPower::PowerSuspend)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

bool SessionManagerDBusContext::canLogout()
{
    // 暂时都返回true
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::logoutBtn)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

bool SessionManagerDBusContext::canReboot()
{
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::rebootBtn)
        && m_systemdProvider->canAction(UkuiPower::PowerReboot)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

bool SessionManagerDBusContext::canPowerOff()
{
    if (Ukuilockinfo::getCfgValue(Ukuilockinfo::buttonType::shutdownBtn)
        && m_systemdProvider->canAction(UkuiPower::PowerShutdown)) {
        return true;
    }

    return false; // GCOV_EXCL_LINE
}

// GCOV_EXCL_START:The interface is to other applications through remote calls, it is inconvenient to use a single test
// method to execute
Q_NOREPLY void SessionManagerDBusContext::switchUser()
{
    m_systemdProvider->doAction(UkuiPower::PowerSwitchUser); // GCOV_EXCL_LINE
}

Q_NOREPLY void SessionManagerDBusContext::switchToUser(QString strUserName)
{
    if (canSwitch()) {
        m_ukuiProvider->doLSAction(UkuiPower::PowerSwitchToUser, strUserName);
    } else {
        qDebug() << "Can't switch user";
    }
}

Q_NOREPLY void SessionManagerDBusContext::hibernate()
{
    if (isInnerCaller()) {
        m_systemdProvider->doAction(UkuiPower::PowerHibernate); // GCOV_EXCL_LINE
    } else {
        m_ukuiProvider->doLSAction(UkuiPower::PowerHibernate);
    }
}

Q_NOREPLY void SessionManagerDBusContext::suspend()
{
    if (isInnerCaller()) {
        m_systemdProvider->doAction(UkuiPower::PowerSuspend); // GCOV_EXCL_LINE
    } else {
        qDebug() << "exec ukui-session-tools suspend";
        QProcess *process = new QProcess(this);
        process->start("ukui-session-tools", QStringList() << "--suspend");
    }
}

Q_NOREPLY void SessionManagerDBusContext::logout()
{
    if (isInnerCaller()) {
        qDebug() << "ukui-session logout interface called";
        if (mManager->getIsShutingDown()) {
            qDebug() << "already performing logout";
            return;
        }

        mManager->setIsShutingDown(true);

        QDBusInterface ukuismserverFace(
            "org.ukui.ukuismserver", "/UKUISMServer", "org.ukui.ukuismserver", QDBusConnection::sessionBus());

        if (!ukuismserverFace.isValid()) {
            qDebug() << "ukuisminterface not valid";
            return;
        }

        // 分级冻结应用唤醒
        QDBusInterface face(
            "com.kylin.ProcessManager",
            "/com/kylin/ProcessManager/AppLauncher",
            "com.kylin.ProcessManager.AppLauncher",
            QDBusConnection::sessionBus());
        if (!face.isValid()) {
            qDebug() << "AppManager interface not valid";
        } else {
            QDBusReply<bool> reply = face.call("ThawFrozenProcesses");
        }

        // QDBusAbstractInterface有超时机制，默认是25秒，25秒后没有返回值，会给出一个带有错误信息的返回值，供调用方判断做出下一步动作，也正是因此KDE桌面不会在某个应用的提醒保存页面一直
        // 停留，而是会继续往下执行注销操作，可以通过setTimerout设置超时时间，实验证明确实如此
        QList<QVariant> argumentList;
        QDBusPendingReply<bool> closeSessionReply
            = ukuismserverFace.asyncCallWithArgumentList(QStringLiteral("closeSession"), argumentList);
        auto watcher = new QDBusPendingCallWatcher(closeSessionReply, this);
        connect(watcher, &QDBusPendingCallWatcher::finished, this, [closeSessionReply, watcher, this]() {
            watcher->deleteLater();
            if (closeSessionReply.isError()) {
                qDebug() << "ukuismserver failed to complete logout with error" << closeSessionReply.error().name()
                         << " continuining with logout";
                ukuiServerComplete("logout");
            }
            if (closeSessionReply.value()) {
                qDebug() << "ukuismserver close session completed";
                ukuiServerComplete("logout");
            } else {
                mManager->setIsShutingDown(false);
                qDebug() << "logout cancelled";
            }
        });
    } else {
        qDebug() << "exec ukui-session-tools logout";
        QProcess *process = new QProcess(this);
        process->start("ukui-session-tools", QStringList() << "--logout");
    }
}

Q_NOREPLY void SessionManagerDBusContext::reboot()
{
    if (isInnerCaller()) {
        qDebug() << "ukui-session reboot interface called";
        if (mManager->getIsShutingDown()) {
            qDebug() << "already performing reboot";
            return;
        }

        mManager->setIsShutingDown(true);

        QDBusInterface ukuismserverFace(
            "org.ukui.ukuismserver", "/UKUISMServer", "org.ukui.ukuismserver", QDBusConnection::sessionBus());

        if (!ukuismserverFace.isValid()) {
            qDebug() << "ukuisminterface not valid";
            return;
        }

        // 分级冻结应用唤醒
        QDBusInterface face(
            "com.kylin.ProcessManager",
            "/com/kylin/ProcessManager/AppLauncher",
            "com.kylin.ProcessManager.AppLauncher",
            QDBusConnection::sessionBus());
        if (!face.isValid()) {
            qDebug() << "AppManager interface not valid";
        } else {
            QDBusReply<bool> reply = face.call("ThawFrozenProcesses");
        }

        // QDBusAbstractInterface有超时机制，默认是25秒，25秒后没有返回值，会给出一个带有错误信息的返回值，供调用方判断做出下一步动作，也正是因此KDE桌面不会在某个应用的提醒保存页面一直
        // 停留，而是会继续往下执行注销操作，可以通过setTimerout设置超时时间，实验证明确实如此
        QList<QVariant> argumentList;
        QDBusPendingReply<bool> closeSessionReply
            = ukuismserverFace.asyncCallWithArgumentList(QStringLiteral("closeSession"), argumentList);
        auto watcher = new QDBusPendingCallWatcher(closeSessionReply, this);
        connect(watcher, &QDBusPendingCallWatcher::finished, this, [closeSessionReply, watcher, this]() {
            watcher->deleteLater();
            if (closeSessionReply.isError()) {
                qDebug() << "ukuismserver failed to complete logout with error" << closeSessionReply.error().name()
                         << " continuining with reboot";
                ukuiServerComplete("reboot");
            }
            if (closeSessionReply.value()) {
                qDebug() << "ukuismserver close session completed";
                ukuiServerComplete("reboot");
            } else {
                mManager->setIsShutingDown(false);
                qDebug() << "logout cancelled";
            }
        });
    } else {
        qDebug() << "exec ukui-session-tools reboot";
        QProcess *process = new QProcess(this);
        process->start("ukui-session-tools", QStringList() << "--reboot");
    }
}

Q_NOREPLY void SessionManagerDBusContext::powerOff()
{
    if (isInnerCaller()) {
        qDebug() << "ukui-session reboot interface called";
        if (mManager->getIsShutingDown()) {
            qDebug() << "already performing poweroff";
            return;
        }

        mManager->setIsShutingDown(true); // GCOV_EXCL_LINE

        QDBusInterface ukuismserverFace(
            "org.ukui.ukuismserver", "/UKUISMServer", "org.ukui.ukuismserver", QDBusConnection::sessionBus());

        if (!ukuismserverFace.isValid()) {           // GCOV_EXCL_LINE
            qDebug() << "ukuisminterface not valid"; // GCOV_EXCL_LINE
            return;                                  // GCOV_EXCL_LINE
        }

        // 分级冻结应用唤醒
        QDBusInterface face(
            "com.kylin.ProcessManager",
            "/com/kylin/ProcessManager/AppLauncher",
            "com.kylin.ProcessManager.AppLauncher",
            QDBusConnection::sessionBus());
        if (!face.isValid()) {
            qDebug() << "AppManager interface not valid";
        } else {
            QDBusReply<bool> reply = face.call("ThawFrozenProcesses");
        }

        // QDBusAbstractInterface有超时机制，默认是25秒，25秒后没有返回值，会给出一个带有错误信息的返回值，供调用方判断做出下一步动作，也正是因此KDE桌面不会在某个应用的提醒保存页面一直
        // 停留，而是会继续往下执行注销操作，可以通过setTimerout设置超时时间，实验证明确实如此
        QList<QVariant> argumentList;
        QDBusPendingReply<bool> closeSessionReply
            = ukuismserverFace.asyncCallWithArgumentList(QStringLiteral("closeSession"), argumentList);
        auto watcher = new QDBusPendingCallWatcher(closeSessionReply, this);
        connect(watcher, &QDBusPendingCallWatcher::finished, this, [closeSessionReply, watcher, this]() {
            watcher->deleteLater();
            if (closeSessionReply.isError()) {
                qDebug() << "ukuismserver failed to complete logout with error" << closeSessionReply.error().name()
                         << " continuining with powerOff";
                ukuiServerComplete("shutdown");
            }
            if (closeSessionReply.value()) {
                qDebug() << "ukuismserver close session completed";
                ukuiServerComplete("shutdown");
            } else {
                mManager->setIsShutingDown(false);
                qDebug() << "logout cancelled";
            }
        });
    } else {
        qDebug() << "exec ukui-session-tools --shutdown";
        QProcess *process = new QProcess(this);
        process->start("ukui-session-tools", QStringList() << "--shutdown");
    }
}

void SessionManagerDBusContext::ukuiServerComplete(QString type)
{
    QDBusInterface wlcomFace(
        WLCOM_SERVICE_BUSNAME, WLCOM_SERVICE_PATH, WLCOM_SERVICE_INTERFACE, QDBusConnection::sessionBus());

    if (!wlcomFace.isValid()) {            // GCOV_EXCL_LINE
        qDebug() << "wlcomface not valid"; // GCOV_EXCL_LINE
        if (type == "logout") {
            logoutComplete();
        } else if (type == "shutdown") {
            shutdownComplete();
        } else if (type == "reboot") {
            rebootComplete();
        }
    } else {
        QList<QVariant> argumentList;
        QDBusPendingReply<bool> closeWindowsReply
            = wlcomFace.asyncCallWithArgumentList(QStringLiteral("CloseWindows"), argumentList);
        auto watcher = new QDBusPendingCallWatcher(closeWindowsReply, this);
        connect(watcher, &QDBusPendingCallWatcher::finished, this, [closeWindowsReply, watcher, type, this]() {
            watcher->deleteLater();
            if (closeWindowsReply.isError()) {
                qDebug() << "wlcom failed to complete close window" << closeWindowsReply.error().name();
                mManager->setIsShutingDown(false);
            }
            if (closeWindowsReply.value()) {
                qDebug() << "wlcom close window completed";
                if (type == "logout") {
                    logoutComplete();
                } else if (type == "shutdown") {
                    shutdownComplete();
                } else if (type == "reboot") {
                    rebootComplete();
                }
            } else {
                qDebug() << "logout cancelled";
            }
        });
    }
}

Q_NOREPLY void SessionManagerDBusContext::startModule(const QString &name)
{
    mManager->startProcess(name, true);
}

Q_NOREPLY void SessionManagerDBusContext::stopModule(const QString &name)
{
    mManager->stopProcess(name);
}

bool SessionManagerDBusContext::startApp(const QString &name, const QStringList &args)
{
    return mManager->startProcess(name, args);
}

uint SessionManagerDBusContext::Inhibit(QString app_id, quint32 toplevel_xid, QString reason, quint32 flags)
{
    uint result = minhibit->addInhibit(app_id, toplevel_xid, reason, flags);
    if (result < 0) {
        return 0;
    }

    QString dbusService = message().service();
    qDebug() << "SessionManagerDBusContext message().service():" << dbusService;

    QStringList keys = m_hashInhibitionServices.keys();
    if (!keys.contains(dbusService)) {
        QList<quint32> cookies;
        cookies.append(result);
        m_hashInhibitionServices.insert(dbusService, cookies);
        m_serviceWatcher->addWatchedService(dbusService);
        qDebug() << "m_serviceWatcher services:..." << m_serviceWatcher->watchedServices();
    } else {
        for (auto iter = m_hashInhibitionServices.begin(); iter != m_hashInhibitionServices.end(); iter++) {
            qDebug() << "Inhibit iter.key()" << iter.key() << dbusService;

            if (iter.key() == dbusService) {
                QList<quint32> cookies = iter.value();
                if (!cookies.contains(result)) {
                    cookies.append(result);
                    m_hashInhibitionServices[dbusService] = cookies;
                    break;
                }
            }
        }
    }
    qDebug() << "Inhibit m_hashInhibitionServices..." << m_hashInhibitionServices;
    emit this->inhibitadded(flags);
    return result;
}

Q_NOREPLY void SessionManagerDBusContext::Uninhibit(uint cookie)
{
    uint result = minhibit->unInhibit(cookie);
    if (result > 0) {
        emit inhibitremove(result);
    }
    for (auto iter = m_hashInhibitionServices.begin(); iter != m_hashInhibitionServices.end(); iter++) {
        QList<quint32> cookies = iter.value();
        for (int i = 0; i < cookies.length(); i++) {
            if (cookie == cookies[i]) {
                qDebug() << "Uninhibit cookies:" << cookies << "cookie:" << cookie;
                if (cookies.length() > 1) {
                    cookies.removeAt(i);
                    m_hashInhibitionServices[iter.key()] = cookies;
                } else {
                    m_serviceWatcher->removeWatchedService(iter.key());
                    m_hashInhibitionServices.remove(iter.key());
                    qDebug() << "Uninhibit m_hashInhibitionServices...:" << m_hashInhibitionServices;
                }
                qDebug() << "Uninhibit m_hashInhibitionServices:" << m_hashInhibitionServices;
                return;
            }
        }
    }
}

QStringList SessionManagerDBusContext::GetInhibitors()
{
    return minhibit->getInhibitor();
}

QVector<InhibitInfo::InhibitorInfo> SessionManagerDBusContext::ListInhibitor(QString type)
{
    QVector<InhibitInfo::InhibitorInfo> result;

    if (type == QString("logout")) {
        result = Ukuilockinfo::listInhibitorInfo(Ukuilockinfo::InhibitorType::logout);
    } else if (type == QString("sleep")) {
        result = Ukuilockinfo::listInhibitorInfo(Ukuilockinfo::InhibitorType::suspend);
    } else if (type == QString("shutdown")) {
        result = Ukuilockinfo::listInhibitorInfo(Ukuilockinfo::InhibitorType::shutdown);
    }

    return result;
}

bool SessionManagerDBusContext::IsSessionRunning()
{
    QString xdg_session_desktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
    if (xdg_session_desktop == "ukui" || xdg_session_desktop == "ukui-wayland") {
        return true;
    }
    return false;
}

QString SessionManagerDBusContext::GetSessionName()
{
    QString xdg_session_desktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
    if (xdg_session_desktop == "ukui" || xdg_session_desktop == "ukui-wayland"
        || xdg_session_desktop == "kylin-wlcom") {
        return "ukui-session";
    }

    return "error";
}

bool SessionManagerDBusContext::IsInhibited(quint32 flags)
{
    return minhibit->isInhibited(flags);
}

void SessionManagerDBusContext::setSessionEnv(const QString &key, const QString &value)
{
    qDebug() << "set env " << key << " as " << value;
    qputenv(key.toLatin1(), value.toLatin1());
}

Q_NOREPLY void SessionManagerDBusContext::emitStartLogout()
{
    qDebug() << "emit  StartLogout";
    emit StartLogout();
}

Q_NOREPLY void SessionManagerDBusContext::emitPrepareForSwitchuser()
{
    qDebug() << "emit  PrepareForSwitchuser";
    emit PrepareForSwitchuser();
}

Q_NOREPLY void SessionManagerDBusContext::emitPrepareForPhase2()
{
    qDebug() << "emit  PrepareForPhase2";
    emit PrepareForPhase2();
}

Q_NOREPLY void SessionManagerDBusContext::simulateUserActivity()
{
    qDebug() << "simulate User Activity";
    KIdleTime::instance()->simulateUserActivity();
}

void SessionManagerDBusContext::on_serviceUnregistered(const QString &serviceName)
{
    qDebug() << "onServiceUnregistered..." << serviceName;

    for (auto iter = m_hashInhibitionServices.begin(); iter != m_hashInhibitionServices.end(); iter++) {
        if (iter.key() == serviceName) {
            QList<quint32> cookies = iter.value();
            for (auto i = 0; i < cookies.length(); i++) {
                quint32 cookie = cookies[i];
                qDebug() << "on_serviceUnregistered cookie:" << cookie;
                Uninhibit(cookie);
            }
            return;
        }
    }
    qDebug() << "on_serviceUnregistered unfind serviceName:" << serviceName;
}
// GCOV_EXCL_STOP

void SessionManagerDBusContext::executeBoxadm()
{
    QProcess *proc = new QProcess;
    QString argu = "--lockall";
    proc->start("boxadm", QStringList{ argu });
    proc->waitForFinished(-1);
    delete proc;
}

// 退出ukui-session.target
void SessionManagerDBusContext::stopUkuiSessionTarget()
{
    auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"),
                                                QStringLiteral("/org/freedesktop/systemd1"),
                                                QStringLiteral("org.freedesktop.systemd1.Manager"),
                                                QStringLiteral("StopUnit"));
    msg << QStringLiteral("ukui-session.target") << QStringLiteral("fail");
    QDBusConnection::sessionBus().call(msg);
}

// GCOV_EXCL_START:The interface is to other applications through remote calls, it is inconvenient to use a single test
// method to execute
void SessionManagerDBusContext::logoutComplete()
{
    // 注销前对文件保护箱加锁
    executeBoxadm();

    // 注销前执行指定目录脚本
    QStringList list = listFileList();
    if (list.isEmpty()) {
        qDebug() << "logouting file list is empty or dir is not exits.";
    } else {
        execPro(list);
    }

    // 调用logout
    qDebug() << "complete xsmp logout, call Terminal";

    if (m_strSessionPath.isEmpty()) {
        QDBusInterface dbus(
            "org.freedesktop.login1",
            "/org/freedesktop/login1",
            "org.freedesktop.login1.Manager",
            QDBusConnection::systemBus());
        if (!dbus.isValid()) {
            qWarning() << "dbusCall: QDBusInterface is invalid org.freedesktop.login1";
            return;
        }

        QDBusReply<QDBusObjectPath> reply = dbus.call("GetSession", "auto");

        if (!reply.isValid()) {
            qDebug() << "GetSession error:" << reply.error().name() << reply.error().message();
            return;
        }
        m_strSessionPath = reply.value().path();
    }

    QDBusInterface interface("org.freedesktop.login1", m_strSessionPath, "org.freedesktop.login1.Session" , QDBusConnection::systemBus());
    if (!interface.isValid()) {
        qWarning() << "dbusCall: QDBusInterface is invalid org.freedesktop.login1" ;
        return ;
    }

    interface.asyncCall("Terminate");

    stopUkuiSessionTarget();
}

void SessionManagerDBusContext::rebootComplete()
{
    // 调用systemd的reboot
    qDebug() << "complete xsmp logout, call Reboot";
    QDBusInterface dbus(
        "org.freedesktop.login1",
        "/org/freedesktop/login1",
        "org.freedesktop.login1.Manager",
        QDBusConnection::systemBus());
    if (!dbus.isValid()) {
        qWarning() << "dbusCall: QDBusInterface is invalid org.freedesktop.login1";
        return;

    }

    QDBusPendingReply<QString> reply;
    if (true) {
        reply = dbus.asyncCallWithArgumentList("Reboot", {QVariant(true)});
    } else {
        reply = dbus.asyncCall("Reboot");
    }
    auto watcher = new QDBusPendingCallWatcher(reply, this);
    connect(watcher, &QDBusPendingCallWatcher::finished,this, [reply, watcher]() {
        watcher->deleteLater();
        if (reply.isError()) {
            qWarning() << "Debus error: " << reply.error();
        }
        if (!reply.value().isEmpty()) {
            QString ret = reply.value();
            if (ret == QLatin1String("yes") || ret == QLatin1String("challenge"))
            {
                qDebug() << "call systemd reboot success";
            }
        } else {
            qDebug() << "call systemd reboot failed";
        }
    });
    stopUkuiSessionTarget();
}

void SessionManagerDBusContext::shutdownComplete()
{
    // 调用systemd的shutdown
    qDebug() << "complete xsmp logout, call powerOff";
    QDBusInterface dbus(
        "org.freedesktop.login1",
        "/org/freedesktop/login1",
        "org.freedesktop.login1.Manager",
        QDBusConnection::systemBus());
    if (!dbus.isValid()) {
        qWarning() << "dbusCall: QDBusInterface is invalid org.freedesktop.login1";
        return;
    }

    QDBusPendingReply<QString> reply;
    if (true) {
        reply = dbus.asyncCallWithArgumentList("PowerOff", { QVariant(true) });
    } else {
        reply = dbus.asyncCall("PowerOff");
    }
    auto watcher = new QDBusPendingCallWatcher(reply, this);
    connect(watcher, &QDBusPendingCallWatcher::finished, this, [reply, watcher]() {
        watcher->deleteLater();
        if (reply.isError()) {
            qWarning() << "Debus error: " << reply.error();
        }
        if (!reply.value().isEmpty()) {
            QString ret = reply.value();

            if (ret == QLatin1String("yes") || ret == QLatin1String("challenge")) {
                qDebug() << "call systemd shutdown success";
            }
        } else {
            qDebug() << "call systemd shutdown failed";
        }
    });
    stopUkuiSessionTarget();
}
// GCOV_EXCL_STOP

QStringList SessionManagerDBusContext::listFileList()
{
    QDir dir("/etc/ukui/ukui-session/logout/");
    if (!dir.exists()) {
        qWarning("Cannot find the example directory");
        return QStringList();
    }
    dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
    dir.setSorting(QDir::Size | QDir::Reversed);

    QFileInfoList list = dir.entryInfoList();
    QStringList filelist;

    for (int i = list.size() - 1; i >= 0; --i) {
        QFileInfo fileInfo = list.at(i);
        filelist << fileInfo.fileName();
    }
    return filelist;
}

void SessionManagerDBusContext::execPro(QStringList proList)
{
    for (int i = 0; i < proList.size(); ++i) {
        qDebug() << "script name is " << proList.at(i);
        QString pro = "/etc/ukui/ukui-session/logout/" + proList.at(i);
        QProcess *exe = new QProcess();
        exe->execute(pro, QStringList());
        delete exe;
    }

    qDebug() << "script exec complete .";
}

bool SessionManagerDBusContext::isInnerCaller()
{
    QString clientService = message().service();
    QDBusConnectionInterface *intf = connection().interface();
    unsigned int pid = intf->servicePid(clientService).value();
    QFile file(QString("/proc/%1/cmdline").arg(pid));
    if (file.exists() && file.open(QIODevice::ReadOnly)) {
        QString strExePath = QString::fromLocal8Bit(file.readAll()).split('\0').first();
        qDebug() << "exe path:" << strExePath << file.fileName();
        if (QStringList({ "/usr/bin/ukui-screensaver-backend",
                          "/usr/bin/ukui-screensaver-dialog",
                          "/usr/bin/ukui-session-tools" })
                .contains(strExePath)) {
            return true;
        }
    }
    return false;
}
