#include "Message.h"

#include "bus.h"
#include "defs.h"

#include <sdi_toolBox/dateTime/age.h>

using namespace std;
using namespace dBus;
//--------------------------------------------------------------
/* Constructor */
Message::Message(const HashID &messageTypeID, const MessageCategory &category)
{
  // Default initialization
  m_postedAt = std::chrono::steady_clock::now();

  // Set the message parameters
  m_messageTypeID = messageTypeID;
  m_category      = category;
}
//--------------------------------------------------------------
/* Default destructor */
Message::~Message()
{
  // Update the age of the message (to be used when logging the message in the bus)
  if (m_bus)
  {
    const auto finalAge = getAge();
    m_bus->setMessageAge(finalAge);
  }
}
//--------------------------------------------------------------
/* Get the timestamp of when the message was posted */
TimePoint Message::getPostedAt() const
{
  return m_postedAt;
}
//--------------------------------------------------------------
/* Set the message parameters when the message is posted to the bus (to be called by the bus when the message is posted) */
void Message::linkToBus(Bus *bus)
{
  m_bus = bus;
}
//--------------------------------------------------------------
/* Get the age of the message in microseconds */
std::chrono::microseconds Message::getAge() const
{
  const auto now = std::chrono::steady_clock::now();
  const auto age = now - m_postedAt;

  return std::chrono::duration_cast<std::chrono::microseconds>(age);
}
//--------------------------------------------------------------
/* Check if the message is of a specific type */
bool Message::isType(const HashID &eventType) const
{
  return m_messageTypeID == eventType;
}
//--------------------------------------------------------------
/* Get the unique identifier for the message type */
HashID Message::getMessageTypeID() const
{
  return m_messageTypeID;
}
//--------------------------------------------------------------
/* Get the log category of the message */
MessageCategory Message::getCategory() const
{
  return m_category;
}
//--------------------------------------------------------------
/* Serialize the message data to a string */
std::string Message::serializeData() const
{
  return "";
}
//--------------------------------------------------------------
/* Get a string representation of the message for logging purposes */
std::string Message::toString() const
{
  const auto serializedData = serializeData();

  // Determine the age of the message for logging purposes
  string age = "N/A";
  if (m_bus)
  {
    const auto &busStartTimestamp = m_bus->getStartTimestamp();
    const auto  dt                = m_postedAt - busStartTimestamp;
    age                           = Age(dt).toString();
  }

  // Format message output
  auto str = std::format("[{:}] - 0x{:08x} ({:})",
                         age,
                         m_messageTypeID,
                         logCategoryToString(m_category));
  if (!serializedData.empty())
    str += " - " + serializedData;
  return str;
}
//--------------------------------------------------------------
/* Get a formatted log line representation of the message for logging purposes */
std::string Message::toLogLine() const
{
  const auto serializedData = serializeData();

  // Determine the age of the message for logging purposes
  std::chrono::microseconds age{ 0 };
  if (m_bus)
  {
    const auto &busStartTimestamp = m_bus->getStartTimestamp();
    const auto  dt                = m_postedAt - busStartTimestamp;
    age                           = Age(dt).getMicroseconds();
  }

  // Format message output
  auto str = std::format("[{:}] - 0x{:08x} ({:})",
                         age.count(),
                         m_messageTypeID,
                         logCategoryToString(m_category));
  if (!serializedData.empty())
    str += " - " + serializedData;
  return str;
}
//--------------------------------------------------------------
