#pragma once

#include <dBus/dBus.h>
#include <thread>
#include <wx/wx.h>

//--------------------------------------------------------------
class wxDBusCommandEvent : public wxCommandEvent
{
  using MessagePtr = std::shared_ptr<dBus::Message>;

  public:
  wxDBusCommandEvent()                                             = delete;      // Default constructor
  virtual ~wxDBusCommandEvent()                                    = default;     // Default destructor
  wxDBusCommandEvent(const wxDBusCommandEvent &obj)                = delete;      // Copy constructor
  wxDBusCommandEvent(wxDBusCommandEvent &&obj) noexcept            = delete;      // Move constructor
  wxDBusCommandEvent &operator=(const wxDBusCommandEvent &obj)     = delete;      // Copy assignment operator
  wxDBusCommandEvent &operator=(wxDBusCommandEvent &&obj) noexcept = delete;      // Move assignment operator

  explicit wxDBusCommandEvent(dBus::HashID messageTypeID,     // Constructor
                              MessagePtr   message = {});

  [[nodiscard]] wxEvent *Clone() const override;     // Clone method for wxWidgets event system

  // dBus message type management
  [[nodiscard]] dBus::HashID getMessageType() const;                                  // Return the message type ID
  void                       setDbusEventType(const dBus::HashID &messageTypeID);     // Set the message type ID
  void                       makeDbusEventType(const std::string &eventType);         // Set the message type ID based on event type string

  // dBus message payload management
  [[nodiscard]] bool       hasMessage() const;                        // Check if the event has an associated message
  [[nodiscard]] MessagePtr getMessage() const;                        // Get the associated message casted to a specific type
  void                     setMessage(const MessagePtr &message);     // Set the associated message for the event

  protected:
  dBus::HashID m_messageTypeID;     // Message type ID
  MessagePtr   m_message;           // Store the original dBus message
};
//--------------------------------------------------------------
wxDECLARE_EVENT(EVT_DBUS_EVENT_MESSAGE, wxDBusCommandEvent);

/* --- */

namespace dBus
{
//--------------------------------------------------------------
class wxNode : private dBus::Node
{
  public:
  using MessageID  = dBus::HashID;
  using MessagePtr = std::shared_ptr<dBus::Message>;

  public:
  wxNode() = delete;                                     // Default constructor
  virtual ~wxNode();                                     // Default destructor
  wxNode(const wxNode &obj)                = delete;     // Copy constructor
  wxNode(wxNode &&obj) noexcept            = delete;     // Move constructor
  wxNode &operator=(const wxNode &obj)     = delete;     // Copy assignment operator
  wxNode &operator=(wxNode &&obj) noexcept = delete;     // Move assignment operator

  explicit wxNode(wxWindow *owner, dBus::Bus &bus);     // Constructor

  using Node::subscribe;       // Subscribe to a specific message type
  using Node::unsubscribe;     // Unsubscribe from a specific message type

  // Message reception handler to be overridden by the gui
  // derived class to handle incoming messages from the bus
  virtual void on_receiveMessageFromBus(MessageID messageID, MessagePtr message) = 0;

  using Node::m_bus;     // Reference to the bus this node is connected to

  protected:
  wxWindow *m_owner = nullptr;     // Pointer to the owner window (for posting events to the GUI)

  std::jthread m_eventThread;     // Thread for listening to messages from the bus

  private:
  void startEventThread();     // Start the event thread to listen for messages from the bus
  void stopEventThread();      // Stop the event thread
  void eventThreadLoop();      // Main loop event thread function

  void on_DBusEvent(wxDBusCommandEvent &event);     // Handler for wxDBusCommandEvent events
};
//--------------------------------------------------------------
}     // namespace dBus