#pragma once

#include <QString>
#include <QDBusInterface>

#include "aqsi-commons-qt_global.h"

namespace aqsi {
namespace dbus {
namespace interface {
inline auto const kOrgFreedesktopSystemd1Manager{QStringLiteral("org.freedesktop.systemd1.Manager")};
}  // namespace interface
namespace method {
inline auto const kOrgFreedesktopSystemd1ManagerStartUnit{QStringLiteral("StartUnit")};
inline auto const kOrgFreedesktopSystemd1ManagerStopUnit{QStringLiteral("StopUnit")};
inline auto const kOrgFreedesktopSystemd1ManagerRestartUnit{QStringLiteral("RestartUnit")};
inline auto const kOrgFreedesktopSystemd1ManagerGetUnit{QStringLiteral("GetUnit")};
}  // namespace method
namespace path {
inline auto const kOrgFreedesktopSystemd1{QStringLiteral("/org/freedesktop/systemd1")};
}  // namespace path
namespace service {
inline auto const kOrgFreedesktopSystemd1{QStringLiteral("org.freedesktop.systemd1")};
}  // namespace service

template <typename ReplyType>
AQSICOMMONSQT_EXPORT ReplyType
callDBusMethod(
    QDBusInterface& iface, QString const& method, QDBus::CallMode call_mode = QDBus::CallMode::Block,
    QVariantList const& args = {})
{
    if (not iface.isValid()) {
        auto const error =
            QStringLiteral("Интерфейс D-Bus недоступен: ") + QDBusConnection::systemBus().lastError().message();

        throw std::runtime_error(qPrintable(error));
    }
    ReplyType const reply = iface.callWithArgumentList(call_mode, method, args);
    if (not reply.isValid()) {
        static constexpr auto kErrorMessage{QStringView(u"Ошибка вызова D-Bus метода '%1' : %2 : %3")};
        auto const error{kErrorMessage.arg(method, reply.error().name(), reply.error().message())};

        throw std::runtime_error(qPrintable(error));
    }
    return reply;
}
}  // namespace dbus
namespace systemd {
/** Синхронно запускает сервис systemd
\param [in] name - имя сервиса
\throw std::runtime_error - Бросает исключение при неудачном вызове либо недоступности интерфейса
*/
AQSICOMMONSQT_EXPORT void startSystemdUnit(QString const& name);

/** Запускает сервис systemd асинхронно
\defgroup systemd-async-calls
\param [in] name - имя сервиса
\param [in] success_callback - указатель на метод, который нужно вызвать при успешном запуске сервиса
\param [in] fail_callback - указатель на метод, который нужно вызвать при неуспешном запуске сервиса
\details Не бросает исключений
*/
AQSICOMMONSQT_EXPORT void startSystemdUnit(
    QString const& name, std::function<void()> const& success_callback,
    std::function<void(QString const& error_message)> const& fail_callback) noexcept;

/** Синхронно останавливает сервис systemd
\param [in] name - имя сервиса
\throw std::runtime_error - Бросает исключение при неудачном вызове либо недоступности интерфейса
*/
AQSICOMMONSQT_EXPORT void stopSystemdUnit(QString const& name);

/** Останавливает сервис systemd асинхронно
\param [in] name - имя сервиса
\param [in] success_callback - указатель на метод, который нужно вызвать при успешной остановке сервиса
\param [in] fail_callback - указатель на метод, который нужно вызвать при неуспешной остановке сервиса
\copydetails systemd-async-calls
*/
AQSICOMMONSQT_EXPORT void stopSystemdUnit(
    QString const& name, std::function<void()> const& success_callback,
    std::function<void(QString const& error_message)> const& fail_callback) noexcept;

/** Синхронно перезапускает сервис systemd
\param [in] name - имя сервиса
\throw std::runtime_error - Бросает исключение при неудачном вызове либо недоступности интерфейса
*/
AQSICOMMONSQT_EXPORT void restartSystemdUnit(QString const& name);

/** Перезапускает сервис systemd асинхронно
\param [in] name - имя сервиса
\param [in] success_callback - указатель на метод, который нужно вызвать при успешном перезапуске сервиса
\param [in] fail_callback - указатель на метод, который нужно вызвать при неуспешном перезапуске сервиса
\copydetails systemd-async-calls
*/
AQSICOMMONSQT_EXPORT void restartSystemdUnit(
    QString const& name, std::function<void()> const& success_callback,
    std::function<void(QString const& error_message)> const& fail_callback) noexcept;
}  // namespace systemd
}  // namespace aqsi
