// SPDX-FileCopyrightText: 2021 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "appearancedbusproxy.h"
#include "modules/api/utils.h"

#include <QDBusInterface>
#include <QDBusPendingReply>
#include <QDBusUnixFileDescriptor>
#include <QFile>
#include <QFileInfo>

const QString DaemonService = QStringLiteral("org.deepin.dde.Daemon1");
const QString DaemonPath = QStringLiteral("/org/deepin/dde/Daemon1");
const QString DaemonInterface = QStringLiteral("org.deepin.dde.Daemon1");

AppearanceDBusProxy::AppearanceDBusProxy(QObject *parent)
    : QObject(parent)
    , m_displayInterface(new QDBusInterface("org.deepin.dde.Display1", "/org/deepin/dde/Display1", "org.deepin.dde.Display1", QDBusConnection::sessionBus(), this))
    , m_timeDateInterface(new DDBusInterface("org.freedesktop.timedate1", "/org/freedesktop/timedate1", "org.freedesktop.timedate1", QDBusConnection::systemBus(), this))
    , m_nid(0)
{
    const QString sessionType = qEnvironmentVariable("XDG_SESSION_TYPE");
    if (sessionType == "wayland") {
        m_wmInterface = nullptr;
    } else {
        m_wmInterface = new DDBusInterface("com.deepin.wm", "/com/deepin/wm", "com.deepin.wm", QDBusConnection::sessionBus(), this);
    }
    registerScaleFactorsMetaType();
    QDBusConnection::systemBus().connect(DaemonService, DaemonPath, DaemonInterface, "HandleForSleep", this, SIGNAL(HandleForSleep(bool)));
    QDBusConnection::sessionBus().connect(QStringLiteral("org.deepin.dde.Timedate1"), QStringLiteral("/org/deepin/dde/Timedate1"), QStringLiteral("org.deepin.dde.Timedate1"), "TimeUpdate", this, SIGNAL(TimeUpdate()));

    QDBusConnection::sessionBus().connect("org.deepin.dde.XSettings1","/org/deepin/dde/XSettings1","org.deepin.dde.XSettings1","SetScaleFactorStarted",this,SIGNAL(SetScaleFactorStarted()));
    QDBusConnection::sessionBus().connect("org.deepin.dde.XSettings1","/org/deepin/dde/XSettings1","org.deepin.dde.XSettings1","SetScaleFactorDone",this,SIGNAL(SetScaleFactorDone()));

    QDBusConnection::sessionBus().connect("org.deepin.dde.Display1", "/org/deepin/dde/Display1", "org.freedesktop.DBus.Properties","PropertiesChanged", this, SLOT(onDisplayPropertiesChanged(QDBusMessage)));
    QDBusConnection::sessionBus().connect("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "NotificationClosed", this, SLOT(onNotificationClosed(uint, uint)));
}

void AppearanceDBusProxy::setUserInterface(const QString &userPath)
{
    m_userInterface = QSharedPointer<DDBusInterface>(new DDBusInterface("org.deepin.dde.Accounts1",
                                                                            userPath,
                                                                            "org.deepin.dde.Accounts1.User",
                                                                            QDBusConnection::systemBus(), this));
}

void AppearanceDBusProxy::Notify(const QString &in0, const QString &in2, const QString &summary, const QString &body, const QStringList &options, const QVariantMap &optionMap, int expireTimeout)
{
    QDBusMessage notifyMessage = QDBusMessage::createMethodCall("org.freedesktop.Notifications",
                                                                "/org/freedesktop/Notifications",
                                                                "org.freedesktop.Notifications", "Notify");
    notifyMessage << in0 << m_nid << in2
                  << summary << body << options
                  << optionMap << expireTimeout;
    QDBusConnection::sessionBus().callWithCallback(notifyMessage, this, SLOT(NotifyNid(uint)));
}

void AppearanceDBusProxy::NotifyNid(uint id)
{
    m_nid = id;
}
// wmInterface
QString AppearanceDBusProxy::cursorTheme()
{
    if (m_wmInterface == nullptr) {
        return "";
    }
    return qvariant_cast<QString>(m_wmInterface->property("cursorTheme"));
}

void AppearanceDBusProxy::setcursorTheme(const QString &cursorTheme)
{
    if (m_wmInterface == nullptr) {
        return;
    }
    m_wmInterface->setProperty("cursorTheme", cursorTheme);
}

int AppearanceDBusProxy::cursorSize()
{
    if (m_wmInterface == nullptr) {
        return 0;
    }
    return qvariant_cast<int>(m_wmInterface->property("cursorSize"));
}

void AppearanceDBusProxy::setcursorSize(int cursorSize)
{
    if (m_wmInterface == nullptr) {
        return;
    }
    m_wmInterface->setProperty("cursorSize", cursorSize);
}

int AppearanceDBusProxy::WorkspaceCount()
{
    if (m_wmInterface == nullptr) {
        return 0;
    }
    return QDBusPendingReply<int>(m_wmInterface->asyncCall(QStringLiteral("WorkspaceCount")));
}
QString AppearanceDBusProxy::GetWorkspaceBackgroundForMonitor(int index, const QString &strMonitorName)
{
    if (m_wmInterface == nullptr) {
        return "";
    }
    return QDBusPendingReply<QString>(m_wmInterface->asyncCall(QStringLiteral("GetWorkspaceBackgroundForMonitor"), index, strMonitorName));
}
void AppearanceDBusProxy::SetCurrentWorkspaceBackgroundForMonitor(const QString &uri, const QString &strMonitorName)
{
    if (m_wmInterface == nullptr) {
        return;
    }
    m_wmInterface->asyncCall(QStringLiteral("SetCurrentWorkspaceBackgroundForMonitor"), uri, strMonitorName);
}
void AppearanceDBusProxy::SetDecorationDeepinTheme(const QString &deepinThemeName)
{
    if (m_wmInterface == nullptr) {
        return;
    }
    m_wmInterface->asyncCall(QStringLiteral("SetDecorationDeepinTheme"), deepinThemeName);
}
void AppearanceDBusProxy::ChangeCurrentWorkspaceBackground(const QString &uri)
{
    if (m_wmInterface == nullptr) {
        return;
    }
    m_wmInterface->asyncCall(QStringLiteral("ChangeCurrentWorkspaceBackground"), uri);
}
int AppearanceDBusProxy::GetCurrentWorkspace()
{
    if (m_wmInterface == nullptr) {
        return 0;
    }
    return QDBusPendingReply<int>(m_wmInterface->asyncCall(QStringLiteral("GetCurrentWorkspace")));
}

void AppearanceDBusProxy::SetWorkspaceBackgroundForMonitor(int index, const QString &strMonitorName, const QString &uri)
{
    if (m_wmInterface == nullptr) {
        return;
    }
    m_wmInterface->asyncCall(QStringLiteral("SetWorkspaceBackgroundForMonitor"), index, strMonitorName, uri);
}
// displayInterface
QString AppearanceDBusProxy::primary()
{
    return qvariant_cast<QString>(m_displayInterface->property("Primary"));
}

QList<QDBusObjectPath> AppearanceDBusProxy::monitors()
{
    return qvariant_cast<QList<QDBusObjectPath>>(m_displayInterface->property("Monitors"));
}

QStringList AppearanceDBusProxy::ListEffectiveOutputNames()
{
    return QDBusPendingReply<QStringList>(m_displayInterface->asyncCall(QStringLiteral("ListEffectiveOutputNames")));
}

QStringList AppearanceDBusProxy::ListOutputNames()
{
    return QDBusPendingReply<QStringList>(m_displayInterface->asyncCall(QStringLiteral("ListOutputNames")));
}

bool AppearanceDBusProxy::isConcatScreenEnabled()
{
    return qvariant_cast<bool>(m_displayInterface->property("ConcatScreenEnabled"));
}

QString AppearanceDBusProxy::FindUserById(const QString &uid)
{
    QDBusMessage accountsMessage = QDBusMessage::createMethodCall("org.deepin.dde.Accounts1", "/org/deepin/dde/Accounts1", "org.deepin.dde.Accounts1", "FindUserById");
    accountsMessage << uid;
    return QDBusPendingReply<QString>(QDBusConnection::systemBus().asyncCall(accountsMessage));
}
// userInterface
QStringList AppearanceDBusProxy::desktopBackgrounds()
{
    if (m_userInterface.isNull())
        return QStringList();
    return qvariant_cast<QStringList>(m_userInterface->property("DesktopBackgrounds"));
}

QString AppearanceDBusProxy::greeterBackground()
{
    if (m_userInterface.isNull())
        return QString();
    return qvariant_cast<QString>(m_userInterface->property("GreeterBackground"));
}

void AppearanceDBusProxy::SetCurrentWorkspace(int currentWorkspace)
{
    if (!m_userInterface.isNull())
        m_userInterface->asyncCall(QStringLiteral("SetCurrentWorkspace"), currentWorkspace);
}

void AppearanceDBusProxy::SetDesktopBackgrounds(const QStringList &val)
{
    if (!m_userInterface.isNull())
        m_userInterface->asyncCall(QStringLiteral("SetDesktopBackgrounds"), val);
}

void AppearanceDBusProxy::SetGreeterBackground(const QString &bg)
{
    if (!m_userInterface.isNull())
        m_userInterface->asyncCall(QStringLiteral("SetGreeterBackground"), bg);
}
// timeDateInterface
QString AppearanceDBusProxy::timezone()
{
    return qvariant_cast<QString>(m_timeDateInterface->property("Timezone"));
}

bool AppearanceDBusProxy::nTP()
{
    return qvariant_cast<bool>(m_timeDateInterface->property("NTP"));
}

// imageBlurInterface
void AppearanceDBusProxy::Delete(const QString &file)
{
    QDBusMessage imageBlurMessage = QDBusMessage::createMethodCall("org.deepin.dde.ImageBlur1", "/org/deepin/dde/ImageBlur1", "org.deepin.dde.ImageBlur1", "Delete");
    imageBlurMessage << file;
    QDBusConnection::systemBus().asyncCall(imageBlurMessage);
}

QString AppearanceDBusProxy::Get(const QString &file)
{
    QDBusMessage imageBlurMessage = QDBusMessage::createMethodCall("org.deepin.dde.ImageBlur1", "/org/deepin/dde/ImageBlur1", "org.deepin.dde.ImageBlur1", "Get");
    imageBlurMessage << file;
    return QDBusPendingReply<QString>(QDBusConnection::systemBus().asyncCall(imageBlurMessage));
}
// imageEffectInterface
void AppearanceDBusProxy::Delete(const QString &effect, const QString &filename)
{
    QDBusMessage imageEffectMessage = QDBusMessage::createMethodCall("org.deepin.dde.ImageEffect1", "/org/deepin/dde/ImageEffect1", "org.deepin.dde.ImageEffect1", "Delete");
    imageEffectMessage << effect << filename;
    QDBusConnection::systemBus().asyncCall(imageEffectMessage);
}

QString AppearanceDBusProxy::Get(const QString &effect, const QString &filename)
{
    QDBusMessage imageEffectMessage = QDBusMessage::createMethodCall("org.deepin.dde.ImageEffect1", "/org/deepin/dde/ImageEffect1", "org.deepin.dde.ImageEffect1", "Get");
    imageEffectMessage << effect << filename;
    QDBusConnection::systemBus().asyncCall(imageEffectMessage);

    return QDBusPendingReply<QString>(QDBusConnection::systemBus().asyncCall(imageEffectMessage));
}
// Daemon1
void AppearanceDBusProxy::DeleteCustomWallPaper(const QString &username, const QString &file)
{
    QDBusMessage daemonMessage = QDBusMessage::createMethodCall(DaemonService, DaemonPath, DaemonInterface, "DeleteCustomWallPaper");
    daemonMessage << username << file;
    QDBusConnection::systemBus().asyncCall(daemonMessage);
}

QStringList AppearanceDBusProxy::GetCustomWallPapers(const QString &username)
{
    QDBusMessage daemonMessage = QDBusMessage::createMethodCall(DaemonService, DaemonPath, DaemonInterface, "GetCustomWallPapers");
    daemonMessage << username;
    return QDBusPendingReply<QStringList>(QDBusConnection::systemBus().asyncCall(daemonMessage));
}

QString AppearanceDBusProxy::SaveCustomWallPaper(const QString &username, const QString &file, const QString &wallpaperType)
{
    QFileInfo wallpaperInfo(file);
    if (!wallpaperInfo.isFile() || !wallpaperInfo.isReadable()) {
        return "";
    }

    QFile wallpaper(file);
    if (!wallpaper.open(QIODevice::ReadOnly)) {
        return "";
    }

    QDBusUnixFileDescriptor fd(wallpaper.handle());
    if (!fd.isValid()) {
        return "";
    }

    QDBusMessage daemonMessage = QDBusMessage::createMethodCall(DaemonService, DaemonPath, DaemonInterface, "SaveCustomWallPaper");
    daemonMessage << username << QVariant::fromValue(fd) << wallpaperType;
    return QDBusPendingReply<QString>(QDBusConnection::systemBus().asyncCall(daemonMessage));
}

void AppearanceDBusProxy::onDisplayPropertiesChanged(const QDBusMessage &message)
{
    if (message.arguments().length() > 1) {
        QVariantMap changedProps = qdbus_cast<QVariantMap>(message.arguments().at(1).value<QDBusArgument>());
        for (QVariantMap::const_iterator it = changedProps.cbegin(); it != changedProps.cend(); ++it) {
            auto prop = it.key().toLatin1() + "Changed";
            if (prop == "PrimaryChanged" || prop == "MonitorsChanged" || prop == "ConcatScreenEnabledChanged") {
                QMetaObject::invokeMethod(this, prop, Qt::DirectConnection, QGenericArgument(it.value().typeName(), it.value().data()));
            }
        }
    }
}

void AppearanceDBusProxy::onNotificationClosed(uint id, uint reason)
{
    Q_UNUSED(reason)
    // reset m_nid after notification closure
    if (id == m_nid)
        m_nid = 0;
}

void AppearanceDBusProxy::SetScaleFactor(double scale)
{
    if (utils::isTreeland()) {
        qWarning() << "treeland env, skip set scale to xsettings";
        return;
    }
    QDBusInterface iface("org.deepin.dde.XSettings1", "/org/deepin/dde/XSettings1", "org.deepin.dde.XSettings1", QDBusConnection::sessionBus());
    iface.asyncCall(QStringLiteral("SetScaleFactor"), scale);
}

void AppearanceDBusProxy::SetScreenScaleFactors(const ScaleFactors &factors)
{
    if (utils::isTreeland()) {
        qWarning() << "treeland env, skip get scale from xsettings";
        return;
    }
    QDBusInterface iface("org.deepin.dde.XSettings1", "/org/deepin/dde/XSettings1", "org.deepin.dde.XSettings1", QDBusConnection::sessionBus());
    iface.asyncCall(QStringLiteral("SetScreenScaleFactors"), QVariant::fromValue(factors));
}
