#include <sdbusplus/async.hpp>

#include <iostream>
#include <string>
#include <variant>
#include <vector>

auto startup(sdbusplus::async::context& ctx) -> sdbusplus::async::task<>
{
    // Create a proxy to the systemd manager object.
    constexpr auto systemd = sdbusplus::async::proxy()
                                 .service("org.freedesktop.systemd1")
                                 .path("/org/freedesktop/systemd1")
                                 .interface("org.freedesktop.systemd1.Manager");

    // Call ListUnitFiles method.
    using ret_type = std::vector<std::tuple<std::string, std::string>>;
    for (auto& [file, status] :
         co_await systemd.call<ret_type>(ctx, "ListUnitFiles"))
    {
        std::cout << file << " " << status << std::endl;
    }

    // Get the Architecture property.
    std::cout << co_await systemd.get_property<std::string>(ctx, "Architecture")
              << std::endl;

    // Get all the properties.
    using variant_type =
        std::variant<bool, std::string, std::vector<std::string>, uint64_t,
                     int32_t, uint32_t, double>;
    for (auto& [property, value] :
         co_await systemd.get_all_properties<variant_type>(ctx))
    {
        std::cout << property << " is "
                  << std::visit(
                         // Convert the variant member to a string for printing.
                         [](auto v) {
            if constexpr (std::is_same_v<std::remove_cvref_t<decltype(v)>,
                                         std::vector<std::string>>)
            {
                return std::string{"Array"};
            }
            else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(v)>,
                                              std::string>)
            {
                return v;
            }
            else
            {
                return std::to_string(v);
            }
        },
                         value)
                  << std::endl;
    }

    // Try to set the Architecture property (which won't work).
    try
    {
        co_await systemd.set_property(ctx, "Architecture", "arm64");
    }
    catch (const std::exception& e)
    {
        std::cout << "Caught exception because you cannot set Architecture: "
                  << e.what() << std::endl;
    }

    // Create a match for the NameOwnerChanged signal.
    namespace rules = sdbusplus::bus::match::rules;
    auto match = sdbusplus::async::match(ctx, rules::nameOwnerChanged());

    // Listen for the signal 4 times...
    for (size_t i = 0; i < 4; ++i)
    {
        auto [service, old_name, new_name] =
            co_await match.next<std::string, std::string, std::string>();

        if (!new_name.empty())
        {
            std::cout << new_name << " owns " << service << std::endl;
        }
        else
        {
            std::cout << service << " released" << std::endl;
        }
    }

    // We are all done, so shutdown the server.
    ctx.request_stop();

    co_return;
}

int main()
{
    sdbusplus::async::context ctx;
    ctx.spawn(startup(ctx));
    ctx.run();

    return 0;
}
