//SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
//
//SPDX-License-Identifier: GPL-3.0-or-later
#include "datetimedbusproxy.h"

#include <QMetaObject>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusPendingReply>
#include <QDateTime>
#include <QLoggingCategory>

Q_LOGGING_CATEGORY(DdcDateTimeDbusProxy, "dcc-datetime-dbusproxy")

const QString TimedateService = QStringLiteral("org.deepin.dde.Timedate1");
const QString TimedatePath = QStringLiteral("/org/deepin/dde/Timedate1");
const QString TimedateInterface = QStringLiteral("org.deepin.dde.Timedate1");

const QString SystemTimedatedService = QStringLiteral("org.deepin.dde.Timedate1");
const QString SystemTimedatedPath = QStringLiteral("/org/deepin/dde/Timedate1");
const QString SystemTimedatedInterface = QStringLiteral("org.deepin.dde.Timedate1");

const QString PropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties");
const QString PropertiesChanged = QStringLiteral("PropertiesChanged");

const QString LangSelectorService = QStringLiteral("org.deepin.dde.LangSelector1");
const QString LangSelectorPath = QStringLiteral("/org/deepin/dde/LangSelector1");
const QString LangSelectorInterface = QStringLiteral("org.deepin.dde.LangSelector1");

DatetimeDBusProxy::DatetimeDBusProxy(QObject *parent)
    : QObject(parent)
    , m_localeInter(new QDBusInterface(LangSelectorService, LangSelectorPath, LangSelectorInterface, QDBusConnection::sessionBus(), this))
    , m_timedateInter(new QDBusInterface(TimedateService, TimedatePath, TimedateInterface, QDBusConnection::sessionBus(), this))
    , m_systemtimedatedInter(new QDBusInterface(SystemTimedatedService, SystemTimedatedPath, SystemTimedatedInterface, QDBusConnection::systemBus(), this))
{
    registerZoneInfoMetaType();

    qRegisterMetaType<LocaleInfo>("LocaleInfo");
    qDBusRegisterMetaType<LocaleInfo>();

    qRegisterMetaType<LocaleList>("LocaleList");
    qDBusRegisterMetaType<LocaleList>();
    QDBusConnection::sessionBus().connect(TimedateService, TimedatePath, PropertiesInterface, PropertiesChanged, this, SLOT(onPropertiesChanged(QDBusMessage)));
}

bool DatetimeDBusProxy::use24HourFormat()
{
    return qvariant_cast<bool>(m_timedateInter->property("Use24HourFormat"));
}
void DatetimeDBusProxy::setUse24HourFormat(bool value)
{
    m_timedateInter->setProperty("Use24HourFormat", QVariant::fromValue(value));
}

int DatetimeDBusProxy::weekdayFormat()
{
    return qvariant_cast<int>(m_timedateInter->property("WeekdayFormat"));
}
void DatetimeDBusProxy::setWeekdayFormat(int value)
{
    m_timedateInter->setProperty("WeekdayFormat", QVariant::fromValue(value));
}

int DatetimeDBusProxy::longDateFormat()
{
    return qvariant_cast<int>(m_timedateInter->property("LongDateFormat"));
}
void DatetimeDBusProxy::setLongDateFormat(int value)
{
    m_timedateInter->setProperty("LongDateFormat", QVariant::fromValue(value));
}

int DatetimeDBusProxy::shortDateFormat()
{
    return qvariant_cast<int>(m_timedateInter->property("ShortDateFormat"));
}
void DatetimeDBusProxy::setShortDateFormat(int value)
{
    m_timedateInter->setProperty("ShortDateFormat", QVariant::fromValue(value));
}

int DatetimeDBusProxy::longTimeFormat()
{
    return qvariant_cast<int>(m_timedateInter->property("LongTimeFormat"));
}
void DatetimeDBusProxy::setLongTimeFormat(int value)
{
    m_timedateInter->setProperty("LongTimeFormat", QVariant::fromValue(value));
}

int DatetimeDBusProxy::shortTimeFormat()
{
    return qvariant_cast<int>(m_timedateInter->property("ShortTimeFormat"));
}
void DatetimeDBusProxy::setShortTimeFormat(int value)
{
    m_timedateInter->setProperty("ShortTimeFormat", QVariant::fromValue(value));
}

int DatetimeDBusProxy::weekBegins()
{
    return qvariant_cast<int>(m_timedateInter->property("WeekBegins"));
}
void DatetimeDBusProxy::setWeekBegins(int value)
{
    m_timedateInter->setProperty("WeekBegins", QVariant::fromValue(value));
}

QString DatetimeDBusProxy::nTPServer()
{
    return qvariant_cast<QString>(m_timedateInter->property("NTPServer"));
}

QString DatetimeDBusProxy::timezone()
{
    return qvariant_cast<QString>(m_timedateInter->property("Timezone"));
}

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

QStringList DatetimeDBusProxy::userTimezones()
{
    return qvariant_cast<QStringList>(m_timedateInter->property("UserTimezones"));
}

void DatetimeDBusProxy::onPropertiesChanged(const QDBusMessage &message)
{
    QVariantMap changedProps = qdbus_cast<QVariantMap>(message.arguments().at(1).value<QDBusArgument>());
    for (QVariantMap::const_iterator it = changedProps.cbegin(); it != changedProps.cend(); ++it) {
        QMetaObject::invokeMethod(this, it.key().toLatin1() + "Changed", Qt::DirectConnection, QGenericArgument(it.value().typeName(), it.value().data()));
    }
}

// Timedate
void DatetimeDBusProxy::SetNTP(bool useNTP)
{
    m_timedateInter->asyncCall(QStringLiteral("SetNTP"), useNTP);
}
void DatetimeDBusProxy::SetNTP(bool useNTP, QObject *receiver, const char *member, const char *errorSlot)
{
    QList<QVariant> argumentList;
    argumentList << QVariant::fromValue(useNTP);
    m_timedateInter->callWithCallback(QStringLiteral("SetNTP"), argumentList, receiver, member, errorSlot);
}

void DatetimeDBusProxy::SetDate(int year, int month, int day, int hour, int min, int sec, int nsec)
{
    m_timedateInter->asyncCall(QStringLiteral("SetDate"), year, month, day, hour, min, sec, nsec);
}
void DatetimeDBusProxy::SetDate(const QDateTime &datetime, QObject *receiver, const char *member)
{
    const QDate date = datetime.date();
    const QTime time = datetime.time();
    QList<QVariant> argumentList;
    argumentList << QVariant::fromValue(date.year()) << QVariant::fromValue(date.month()) << QVariant::fromValue(date.day());
    argumentList << QVariant::fromValue(time.hour()) << QVariant::fromValue(time.minute()) << QVariant::fromValue(time.second()) << 0;
    m_timedateInter->callWithCallback(QStringLiteral("SetDate"), argumentList, receiver, member);
}
void DatetimeDBusProxy::DeleteUserTimezone(const QString &zone)
{
    m_timedateInter->asyncCall(QStringLiteral("DeleteUserTimezone"), zone);
}

void DatetimeDBusProxy::AddUserTimezone(const QString &zone)
{
    m_timedateInter->asyncCall(QStringLiteral("AddUserTimezone"), zone);
}

QStringList DatetimeDBusProxy::GetSampleNTPServers()
{
    return QDBusPendingReply<QStringList>(m_timedateInter->asyncCall(QStringLiteral("GetSampleNTPServers")));
}

bool DatetimeDBusProxy::GetSampleNTPServers(QObject *receiver, const char *member)
{
    QList<QVariant> argumentList;
    return m_timedateInter->callWithCallback(QStringLiteral("GetSampleNTPServers"), argumentList, receiver, member);
}

ZoneInfo DatetimeDBusProxy::GetZoneInfo(const QString &zone)
{
    return QDBusPendingReply<ZoneInfo>(m_timedateInter->asyncCall(QStringLiteral("GetZoneInfo"), zone));
}
bool DatetimeDBusProxy::GetZoneInfo(const QString &zone, QObject *receiver, const char *member)
{
    QList<QVariant> argumentList;
    argumentList << QVariant::fromValue(zone);
    return m_timedateInter->callWithCallback(QStringLiteral("GetZoneInfo"), argumentList, receiver, member);
}

// System Timedate
void DatetimeDBusProxy::SetTimezone(const QString &timezone)
{
    m_timedateInter->asyncCall(QStringLiteral("SetTimezone"), timezone);
}

void DatetimeDBusProxy::SetNTPServer(const QString &server, const QString &message)
{
    m_systemtimedatedInter->asyncCall(QStringLiteral("SetNTPServer"), server, message);
}

void DatetimeDBusProxy::SetNTPServer(const QString &server, const QString &message, QObject *receiver, const char *member, const char *errorSlot)
{
    QList<QVariant> argumentList;
    argumentList << QVariant::fromValue(server) << QVariant::fromValue(message);
    m_systemtimedatedInter->callWithCallback(QStringLiteral("SetNTPServer"), argumentList, receiver, member, errorSlot);
}

QString DatetimeDBusProxy::currentLocale()
{
    QDBusInterface dbus(LangSelectorService, LangSelectorPath, LangSelectorInterface, QDBusConnection::sessionBus());
    return qvariant_cast<QString>(dbus.property("CurrentLocale"));
}

std::optional<LocaleList> DatetimeDBusProxy::getLocaleListMap()
{
    QDBusPendingReply<LocaleList> reply = m_localeInter->asyncCall(QStringLiteral("GetLocaleList"));
    reply.waitForFinished();
    if (reply.isError()) {
        qCDebug(DdcDateTimeDbusProxy) << "Can not get localeRegion: "<< reply.error();
        return std::nullopt;
    }
    return reply.value();
}

std::optional<QString> DatetimeDBusProxy::getLocaleRegion()
{
    QDBusPendingReply<QString> reply = m_localeInter->asyncCall(QStringLiteral("GetLocaleRegion"));
    reply.waitForFinished();
    if (reply.isError()) {
        qCDebug(DdcDateTimeDbusProxy) << "Can not get localeRegion: "<< reply.error();
        return std::nullopt;
    }
    if (reply.value().isEmpty()) {
        return std::nullopt;
    } else {
        return reply.value();
    }
}

void DatetimeDBusProxy::setLocaleRegion(const QString &locale)
{
    m_localeInter->asyncCall(QStringLiteral("SetLocaleRegion"), locale);
}
