#pragma once

#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/panel.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/notebook.h>
#include <wx/sizer.h>
#include <wx/frame.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
#include <wx/dataview.h>
#include <wx/stattext.h>
#include <wx/statbox.h>
#include <RumPi/Data/SelectedSensorReadings.h>
#include "../../Headers/LoggerEventForwarder.h"
#include "../../Headers/GUI/ComponentData.h"
#include "../../Headers/GUI/ComponentPanel.h"
#include "../../Headers/GUI/HomeScenePanel.h"
#include "../../Headers/GUI/LoggerListData.h"

//Owned by pointer, so a forward declaration keeps wx/thread.h and the poll-loop details out of this header.
class RumPiManagerThread;

///Custom event carrying a component-data update from the manager thread to the UI.
wxDECLARE_EVENT(wxEVT_RUMPI_UPDATE, wxThreadEvent);

/**
* Menu / control command IDs for the main window.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*/
enum RumPiMenuID
{
	ID_SHOW_LOGS = 52		///< The "Show Log Files" menu item.
};

/**
* The client's main window: a tabbed frame (Home scene, Summary tiles, Devices, Logger, Settings) that starts the
* background poll thread and the alert forwarder, and refreshes its tabs from the events they post.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*/
class MainWindow : public wxFrame
{
protected:
	wxNotebook* myNotebook;				///< The tab container.
	HomeScenePanel* myHomeScenePanel;	///< The Home tab's condition-reactive backdrop.
	wxPanel* mySummaryPanel;			///< The Summary tab (at-a-glance tiles).
	wxPanel* myDevicesPanel;			///< The Devices tab.
	wxPanel* myLoggerPanel;				///< The Logger tab.
	wxPanel* mySettingsPanel;			///< The Settings tab.

	//Devices Panel
	wxGridSizer* myDataViewGridSizer;		///< The grid sizer holding the device tiles.
	wxScrolledWindow* myDevicesScrollWindow;///< The scrollable container for the device tiles.

	//Logger Panel
	wxDataViewCtrl* myLoggerDataViewCtrl;		///< The data-view control showing the log.
	LoggerListData* myLoggerListDataModel;		///< The model backing the log control.
	LoggerEventForwarder* myLoggerEventForwarder;///< Forwards AlertManager alerts to the Logger tab.

	//Summary Panel: the live value label for each at-a-glance tile.
	wxStaticText* myTemperatureValue;		///< The Temperature tile's value label.
	wxStaticText* myHumidityValue;			///< The Humidity tile's value label.
	wxStaticText* myAirQualityValue;		///< The Air Quality tile's value label.
	wxStaticText* myPmTwoPointFiveValue;	///< The PM2.5 tile's value label.
	wxStaticText* myTVOCValue;				///< The TVOC tile's value label.
	wxStaticText* myFormaldehydeValue;		///< The Formaldehyde tile's value label.
	wxStaticText* myCO2Value;				///< The CO2 tile's value label.
	wxStaticText* myMotionValue;			///< The Motion tile's value label.
	wxStaticText* myWindSpeedValue;			///< The Wind Speed tile's value label.
	wxStaticText* myLightValue;				///< The Light tile's value label.

	//One panel per component instance, keyed by the component's unique name (multiple components can share a type,
	//so the name - not the type - is the identity here).
	std::unordered_map<std::string, ComponentPanel*> myComponentDataCollection;

	//Background worker: polls RumPi and posts wxEVT_RUMPI_UPDATE to this window. Owned here so it can be stopped
	//and freed before the window is destroyed - it holds a pointer to us and must not outlive us.
	RumPiManagerThread* myRumPiManagerThread;

	/**
	* Builds the menu bar and status bar and binds the window's menu, update, logger, and close events.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by the constructor.
	* @endcode
	*/
	void ConstructMenuAndStatusBar();

	/**
	* Builds the notebook and its five tabs (Home, Summary, Devices, Logger, Settings) and adds it to the window layout.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by the constructor.
	* @endcode
	*/
	void ConstructNotebook();

	/**
	* Builds the Home tab's condition-reactive scene panel and adds it to the notebook.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by ConstructNotebook().
	* @endcode
	*/
	void ConstructHomePanel();

	/**
	* Builds the Summary tab: a three-per-row grid of at-a-glance sensor tiles, stashing each tile's value label for
	* live updates.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by ConstructNotebook().
	* @endcode
	*/
	void ConstructSummaryPanel();

	/**
	* Builds the Devices tab: a scrollable, three-column grid that will hold one tile per component instance.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by ConstructNotebook().
	* @endcode
	*/
	void ConstructDevicesPanel();

	/**
	* Builds the Logger tab: a data-view control with icon/time/level/description columns, backed by the log model.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by ConstructNotebook().
	* @endcode
	*/
	void ConstructLoggerPanel();

	/**
	* Builds the (currently empty) Settings tab and adds it to the notebook.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by ConstructNotebook().
	* @endcode
	*/
	void ConstructSettingsPanel();

	/**
	* Stops the background poll thread and then tears down the alert forwarder, in that order (stop the producer
	* before the consumer). Null-safe and idempotent, so both OnClose and the destructor can call it.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	TeardownBackgroundWork();
	* @endcode
	*/
	void TeardownBackgroundWork();

	/**
	* Builds one titled summary tile with a large centered value label and adds it to the grid.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	wxStaticText* label = CreateSummaryTile(mySummaryPanel, tileGridSizer, "Temperature");
	* @endcode
	*
	* @param [in] parent        The parent window for the tile.
	* @param [in] tileGridSizer The grid sizer to add the tile to.
	* @param [in] title         The tile's title.
	*
	* @return The tile's value label, for later live updates.
	*/
	wxStaticText* CreateSummaryTile(wxWindow* parent, wxSizer* tileGridSizer, const wxString& title);

	/**
	* Refreshes every summary tile's value label from a sensor snapshot (temperature, humidity, gases, particulates,
	* air quality, motion, wind, and light) and re-flows the tiles.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	UpdateSummaryPanel(readings);
	* @endcode
	*
	* @param [in] readings The sensor snapshot to display.
	*/
	void UpdateSummaryPanel(const RumPi::SelectedSensorReadings& readings);

	/**
	* Close handler: tears down the background work before the window is destroyed (the worker and forwarder both post
	* events to us), then lets the default handler proceed.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Invoked by wxWidgets on a close request.
	* @endcode
	*
	* @param [in] event The close event.
	*/
	virtual void OnClose(wxCloseEvent& event);

	/**
	* Exit handler: closes the window.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Invoked by the File > Exit menu item.
	* @endcode
	*
	* @param [in] event The command event.
	*/
	virtual void OnExit(wxCommandEvent& event);

	/**
	* About handler: shows the application's about dialog.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Invoked by the Help > About menu item.
	* @endcode
	*
	* @param [in] event The command event.
	*/
	virtual void OnAbout(wxCommandEvent& event);

	/**
	* "Show Log Files" handler: opens the log folder in the platform's file manager, falling back to a message box
	* with the path if that isn't possible (e.g. a headless kiosk) or if no log path is available yet.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Invoked by the Help > Show Log Files menu item.
	* @endcode
	*
	* @param [in] event The command event.
	*/
	virtual void OnShowLogs(wxCommandEvent& event);

	/**
	* RumPi-update handler (main thread): refreshes the Summary tiles and Home scene from the event's snapshot, then
	* defensively parses the component JSON payload and creates/refreshes one device tile per named component instance.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Invoked on the main thread when the worker posts a wxEVT_RUMPI_UPDATE.
	* @endcode
	*
	* @param [in] event The thread event carrying the snapshot and component JSON.
	*/
	virtual void OnRumPiUpdate(wxThreadEvent& event);

	/**
	* Parses the component JSON payload and creates/refreshes one device tile per named component instance. Split
	* out of OnRumPiUpdate and called inside a try/catch there so a bad_alloc (newing panels) or a malformed payload
	* can't escape the wx event handler and terminate the app.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Called by OnRumPiUpdate().
	* @endcode
	*
	* @param [in] componentJson The raw component JSON string from the update event.
	*/
	void RefreshDeviceTiles(const std::string& componentJson);

	/**
	* Logger-update handler (main thread): appends the event's log line to the logger model.
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Invoked on the main thread when the forwarder posts a wxEVT_RUMPI_LOGGER_UPDATE.
	* @endcode
	*
	* @param [in] event The thread event carrying the log line.
	*/
	virtual void OnLoggerUpdate(wxThreadEvent& event);

public:
	/**
	* Builds the main window: sets up the menu/status bar and notebook, creates the alert forwarder, and starts the
	* background poll thread (surfacing a failure to start through the alert channel rather than a modal popup).
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	MainWindow* window = new MainWindow(nullptr, wxID_ANY, "MainWindow");
	*	window->Show(true);
	* @endcode
	*
	* @param [in] parent The parent window (nullptr for a top-level frame).
	* @param [in] id     The window identifier.
	* @param [in] title  The window title.
	* @param [in] pos    The initial position.
	* @param [in] size   The initial size.
	* @param [in] style  The frame style flags.
	*/
	MainWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(500, 300), long style = wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL);

	/**
	* Destroys the window, tearing down the background work as a safety net for paths that bypass OnClose (null-safe
	* and idempotent).
	*
	* @author Eddie O'Hagan
	* @date 8/13/2026
	*
	* @code
	*	//Runs when the window is destroyed.
	* @endcode
	*/
	~MainWindow();
};
