/*
 * DWN - Desktop Window Manager
 * Event Bus System
 */

#ifndef WM_EVENT_H
#define WM_EVENT_H

#include "wm_types.h"
#include "wm_client.h"
#include "wm_string.h"

#ifdef __cplusplus
extern "C" {
#endif

/*==============================================================================
 * Event Data Structures
 *============================================================================*/

typedef struct {
    WmEventType type;
    WmTime timestamp;
    WmId source_id;
} WmEventHeader;

/* Window Events */
typedef struct {
    WmEventHeader header;
    AbstractClient *client;
} WmEventWindowBase;

typedef struct {
    WmEventHeader header;
    AbstractClient *client;
} WmEventWindowCreated;

typedef struct {
    WmEventHeader header;
    AbstractClient *client;
    WmString *old_title;
    WmString *new_title;
} WmEventWindowTitleChanged;

typedef struct {
    WmEventHeader header;
    AbstractClient *client;
    WmRect old_geometry;
    WmRect new_geometry;
} WmEventWindowMoved;

typedef struct {
    WmEventHeader header;
    AbstractClient *client;
    WmRect old_geometry;
    WmRect new_geometry;
} WmEventWindowResized;

typedef struct {
    WmEventHeader header;
    AbstractClient *client;
    WmClientFlags old_flags;
    WmClientFlags new_flags;
} WmEventWindowStateChanged;

/* Workspace Events */
typedef struct {
    WmEventHeader header;
    WmWorkspaceId workspace;
} WmEventWorkspaceBase;

typedef struct {
    WmEventHeader header;
    WmWorkspaceId old_workspace;
    WmWorkspaceId new_workspace;
} WmEventWorkspaceSwitched;

typedef struct {
    WmEventHeader header;
    WmWorkspaceId workspace;
    WmLayoutType old_layout;
    WmLayoutType new_layout;
} WmEventWorkspaceLayoutChanged;

typedef struct {
    WmEventHeader header;
    WmWorkspaceId workspace;
    AbstractClient *client;
} WmEventClientWorkspaceChanged;

/* Input Events */
typedef struct {
    WmEventHeader header;
    unsigned int keycode;
    unsigned int keysym;
    unsigned int modifiers;
    const char *key_name;
} WmEventKey;

typedef struct {
    WmEventHeader header;
    unsigned int button;
    int x;
    int y;
    unsigned int modifiers;
} WmEventButton;

typedef struct {
    WmEventHeader header;
    int x;
    int y;
    int delta_x;
    int delta_y;
    unsigned int modifiers;
} WmEventMotion;

typedef struct {
    WmEventHeader header;
    int delta;
    int x;
    int y;
} WmEventScroll;

/* Monitor Events */
typedef struct {
    WmEventHeader header;
    int monitor_index;
    WmRect geometry;
    bool primary;
} WmEventMonitorAdded;

typedef struct {
    WmEventHeader header;
    int monitor_index;
} WmEventMonitorRemoved;

/* Configuration Events */
typedef struct {
    WmEventHeader header;
    WmString *config_path;
    bool success;
    WmString *error_message;
} WmEventConfigReloaded;

/* Command Events */
typedef struct {
    WmEventHeader header;
    WmCommandType command;
    bool success;
    WmString *error_message;
} WmEventCommandExecuted;

/* Custom Event */
typedef struct {
    WmEventHeader header;
    WmString *event_name;
    void *custom_data;
    WmDestroyFunc destroy_func;
} WmEventCustom;

/*==============================================================================
 * Event Bus Lifecycle
 *============================================================================*/

WmEventBus* wm_event_bus_create(void);
void wm_event_bus_destroy(WmEventBus *bus);

WmEventBus* wm_event_bus_get_default(void);
void wm_event_bus_set_default(WmEventBus *bus);

/*==============================================================================
 * Event Subscription
 *============================================================================*/

WmEventSubscription* wm_event_subscribe(WmEventBus *bus, 
                                        WmEventType type,
                                        WmEventHandler handler, 
                                        void *user_data);

WmEventSubscription* wm_event_subscribe_pattern(WmEventBus *bus,
                                                WmEventType type_min,
                                                WmEventType type_max,
                                                WmEventHandler handler,
                                                void *user_data);

WmEventSubscription* wm_event_subscribe_all(WmEventBus *bus,
                                            WmEventHandler handler,
                                            void *user_data);

void wm_event_unsubscribe(WmEventBus *bus, WmEventSubscription *subscription);
void wm_event_unsubscribe_all(WmEventBus *bus, void *user_data);

/*==============================================================================
 * Event Emission
 *============================================================================*/

void wm_event_emit(WmEventBus *bus, WmEventType type, const void *event_data);
void wm_event_emit_async(WmEventBus *bus, WmEventType type, const void *event_data);

/* Convenience emitters */
void wm_event_emit_window_created(WmEventBus *bus, AbstractClient *client);
void wm_event_emit_window_destroyed(WmEventBus *bus, AbstractClient *client);
void wm_event_emit_window_focused(WmEventBus *bus, AbstractClient *client, AbstractClient *prev_focus);
void wm_event_emit_window_moved(WmEventBus *bus, AbstractClient *client, const WmRect *old_geom);
void wm_event_emit_window_resized(WmEventBus *bus, AbstractClient *client, const WmRect *old_geom);
void wm_event_emit_window_state_changed(WmEventBus *bus, AbstractClient *client, 
                                        WmClientFlags old_flags, WmClientFlags new_flags);

void wm_event_emit_workspace_switched(WmEventBus *bus, WmWorkspaceId old_ws, WmWorkspaceId new_ws);
void wm_event_emit_workspace_layout_changed(WmEventBus *bus, WmWorkspaceId ws, 
                                            WmLayoutType old_layout, WmLayoutType new_layout);

/*==============================================================================
 * Event Processing
 *============================================================================*/

void wm_event_process(WmEventBus *bus);
void wm_event_process_all(WmEventBus *bus);
bool wm_event_process_one(WmEventBus *bus);

void wm_event_dispatch_pending(WmEventBus *bus);
int wm_event_get_pending_count(const WmEventBus *bus);

/*==============================================================================
 * Event Data Helpers
 *============================================================================*/

WmEventHeader* wm_event_get_header(void *event_data);
WmTime wm_event_get_timestamp(const void *event_data);
const char* wm_event_type_to_string(WmEventType type);
WmEventType wm_event_type_from_string(const char *str);

/*==============================================================================
 * Event Blocking/Filtering
 *============================================================================*/

void wm_event_begin_block(WmEventBus *bus, WmEventType type);
void wm_event_end_block(WmEventBus *bus, WmEventType type);
bool wm_event_is_blocked(const WmEventBus *bus, WmEventType type);

void wm_event_suppress(WmEventBus *bus, WmEventType type);
void wm_event_unsuppress(WmEventBus *bus, WmEventType type);
bool wm_event_is_suppressed(const WmEventBus *bus, WmEventType type);

/*==============================================================================
 * Custom Events
 *============================================================================*/

void wm_event_emit_custom(WmEventBus *bus, const char *event_name, void *data, WmDestroyFunc destroy_fn);
WmEventSubscription* wm_event_subscribe_custom(WmEventBus *bus, const char *event_name,
                                               WmEventHandler handler, void *user_data);

/*==============================================================================
 * Event Statistics
 *============================================================================*/

uint64_t wm_event_get_emit_count(const WmEventBus *bus, WmEventType type);
uint64_t wm_event_get_total_emit_count(const WmEventBus *bus);
void wm_event_reset_statistics(WmEventBus *bus);

#ifdef __cplusplus
}
#endif

#endif /* WM_EVENT_H */
