#include "../Headers/LoggerEventForwarder.h"
#include "../Headers/GUI/LoggerLineData.h"
#include <memory>
#include <wx/datetime.h>

wxDEFINE_EVENT(wxEVT_RUMPI_LOGGER_UPDATE, wxThreadEvent);

/**
* Subscribes to the AlertManager and stores the given UI handler so every alert is forwarded to it. Keeps the
* subscription handle so the destructor can unsubscribe.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	LoggerEventForwarder forwarder(this);
* @endcode
*
* @param [in] handler The UI event handler to forward alerts to.
*/
LoggerEventForwarder::LoggerEventForwarder(wxEvtHandler* handler)
{
	myWxEventHandler = handler;

	//Subscribe once. The AlertManager fires this on whichever thread reported the alert, so the callback
	//only builds data and posts it - it never touches the UI directly. Keep the handle so the destructor can
	//unsubscribe (the owner must stop the alert producers first - see MainWindow::TeardownBackgroundWork).
	mySubscriptionId = RumPi::AlertManager::GetInstance().Subscribe([this](const RumPi::AlertEvent& loggerEvent)
	{
		HandleLoggerEvent(loggerEvent);
	});
}

/**
* Unsubscribes from the AlertManager so a later alert can't call into a destroyed forwarder.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	//Runs when the forwarder is destroyed.
* @endcode
*/
LoggerEventForwarder::~LoggerEventForwarder()
{
	//Stop receiving alerts before this object goes away, so a later alert can't call into a destroyed forwarder.
	RumPi::AlertManager::GetInstance().Unsubscribe(mySubscriptionId);
}

/**
* Builds a log line (pure data) from the alert and queues it to the UI handler as a wxEVT_RUMPI_LOGGER_UPDATE, so
* the actual UI update happens on the main thread.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	//Invoked by the AlertManager on whichever thread reported the alert.
* @endcode
*
* @param [in] loggerEvent The alert event to forward.
*/
void LoggerEventForwarder::HandleLoggerEvent(const RumPi::AlertEvent& loggerEvent)
{
	//Build the row (pure data) and hand it to the UI thread via a queued event.
	LoggerLineData logLine(wxDateTime::Now().FormatISOCombined(' '),
						   loggerEvent.GetAlertLevel(),
						   loggerEvent.GetEventSummary());

	//Own the event until wxQueueEvent takes it, so a throw from SetPayload (deep-copying the payload) frees it
	//rather than leaking - and escaping this AlertManager subscriber callback (mirrors RumPiManagerThread::Entry).
	std::unique_ptr<wxThreadEvent> loggerUpdateEvent(new wxThreadEvent(wxEVT_RUMPI_LOGGER_UPDATE));
	loggerUpdateEvent->SetPayload(logLine);
	wxQueueEvent(myWxEventHandler, loggerUpdateEvent.release());
}
