#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/asio/property.hpp>
#include <sdbusplus/bus.hpp>

#include <iostream>

namespace xyz
{
namespace demo
{

const std::string path = "/xyz/demo";
const std::string name = "xyz.demo";

} // namespace demo
} // namespace xyz

namespace name
{

const std::string greetings = "Greetings";
const std::string goodbyes = "Goodbyes";

} // namespace name

namespace utils
{

template <class T>
class Property
{
  public:
    Property(sdbusplus::asio::connection& bus, std::string_view service,
             std::string_view path, std::string_view interface,
             std::string_view name) :
        bus_(bus),
        service_(service), path_(path), interface_(interface), name_(name)
    {}

    template <class OnError, class OnSuccess>
    void async_get(OnError&& onError, OnSuccess&& onSuccess)
    {
        sdbusplus::asio::getProperty<T>(bus_, service_, path_, interface_,
                                        name_, std::forward<OnError>(onError),
                                        std::forward<OnSuccess>(onSuccess));
    }

    template <class OnError, class OnSuccess>
    void async_set(T&& value, OnError&& onError, OnSuccess&& onSuccess)
    {
        sdbusplus::asio::setProperty(
            bus_, service_, path_, interface_, name_, std::forward<T>(value),
            std::forward<OnError>(onError), std::forward<OnSuccess>(onSuccess));
    }

  private:
    sdbusplus::asio::connection& bus_;
    std::string service_;
    std::string path_;
    std::string interface_;
    std::string name_;
};

} // namespace utils

class Application
{
  public:
    Application(boost::asio::io_context& ioc, sdbusplus::asio::connection& bus,
                sdbusplus::asio::object_server& objServer) :
        ioc_(ioc),
        bus_(bus), objServer_(objServer)
    {
        demo_ = objServer_.add_interface(xyz::demo::path, xyz::demo::name);

        demo_->register_property_r(name::greetings, std::string(),
                                   sdbusplus::vtable::property_::const_,
                                   [this](const auto&) { return greetings_; });

        demo_->register_property_rw(
            name::goodbyes, std::string(),
            sdbusplus::vtable::property_::emits_change,
            [this](const auto& newPropertyValue, const auto&) {
                goodbyes_ = newPropertyValue;
                return 1;
            },
            [this](const auto&) { return goodbyes_; });

        demo_->initialize();
    }

    ~Application()
    {
        objServer_.remove_interface(demo_);
    }

    uint32_t fatalErrors() const
    {
        return fatalErrors_;
    }

    auto getFailed()
    {
        return [this](boost::system::error_code error) {
            std::cerr << "Error: getProperty failed " << error << "\n";
            ++fatalErrors_;
        };
    }

    void asyncReadPropertyWithIncorrectType()
    {
        utils::Property<uint32_t> propertyWithWrongType{
            bus_, xyz::demo::name, xyz::demo::path, xyz::demo::name,
            name::greetings};

        propertyWithWrongType.async_get(
            [](boost::system::error_code error) {
                std::cout
                    << "As expected failed to getProperty with wrong type: "
                    << error << "\n";
            },
            [this](uint32_t) {
                std::cerr << "Error: it was expected to fail getProperty due "
                             "to wrong type\n";
                ++fatalErrors_;
            });
    }

    void asyncReadProperties()
    {
        propertyGreetings.async_get(getFailed(), [](std::string value) {
            std::cout << "Greetings value is: " << value << "\n";
        });

        propertyGoodbyes.async_get(getFailed(), [](std::string value) {
            std::cout << "Goodbyes value is: " << value << "\n";
        });
    }

    void asyncChangeProperty()
    {
        propertyGreetings.async_set(
            "Hi, hey, hello",
            [](const boost::system::error_code& error) {
                std::cout << "As expected, failed to set greetings property: "
                          << error << "\n";
            },
            [this]() {
                std::cout
                    << "Error: it was expected to fail to change greetings\n";
                ++fatalErrors_;
            });

        propertyGoodbyes.async_set(
            "Bye bye",
            [this](const boost::system::error_code& error) {
                std::cout << "Error: it supposed to be ok to change goodbyes "
                             "property: "
                          << error << "\n";
                ++fatalErrors_;
            },
            [this]() {
                std::cout << "Changed goodbyes property as expected\n";
                boost::asio::post(ioc_, [this] { asyncReadProperties(); });
            });
    }

  private:
    boost::asio::io_context& ioc_;
    sdbusplus::asio::connection& bus_;
    sdbusplus::asio::object_server& objServer_;

    std::shared_ptr<sdbusplus::asio::dbus_interface> demo_;
    std::string greetings_ = "Hello";
    std::string goodbyes_ = "Bye";

    uint32_t fatalErrors_ = 0u;

    utils::Property<std::string> propertyGreetings{
        bus_, xyz::demo::name, xyz::demo::path, xyz::demo::name,
        name::greetings};
    utils::Property<std::string> propertyGoodbyes{
        bus_, xyz::demo::name, xyz::demo::path, xyz::demo::name,
        name::goodbyes};
};

int main(int, char**)
{
    boost::asio::io_context ioc;
    boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);

    signals.async_wait(
        [&ioc](const boost::system::error_code&, const int&) { ioc.stop(); });

    auto bus = std::make_shared<sdbusplus::asio::connection>(ioc);
    auto objServer = std::make_unique<sdbusplus::asio::object_server>(bus);

    bus->request_name(xyz::demo::name.c_str());

    Application app(ioc, *bus, *objServer);

    boost::asio::post(ioc,
                      [&app] { app.asyncReadPropertyWithIncorrectType(); });
    boost::asio::post(ioc, [&app] { app.asyncReadProperties(); });
    boost::asio::post(ioc, [&app] { app.asyncChangeProperty(); });

    ioc.run();

    std::cout << "Fatal errors count: " << app.fatalErrors() << "\n";

    return app.fatalErrors();
}
