/*
 * DWN - Desktop Window Manager
 * Abstract Client Interface
 */

#ifndef WM_CLIENT_H
#define WM_CLIENT_H

#include "core/wm_types.h"
#include "core/wm_string.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Forward declarations */
typedef struct Client Client;  /* Legacy client structure */

/*==============================================================================
 * Abstract Client Type
 *============================================================================*/

typedef struct AbstractClient AbstractClient;

/*==============================================================================
 * Client State Flags
 *============================================================================*/

typedef enum {
    WM_CLIENT_STATE_NORMAL     = 0,
    WM_CLIENT_STATE_FLOATING   = (1 << 0),
    WM_CLIENT_STATE_FULLSCREEN = (1 << 1),
    WM_CLIENT_STATE_MAXIMIZED  = (1 << 2),
    WM_CLIENT_STATE_MINIMIZED  = (1 << 3),
    WM_CLIENT_STATE_URGENT     = (1 << 4),
    WM_CLIENT_STATE_STICKY     = (1 << 5),
    WM_CLIENT_STATE_HIDDEN     = (1 << 6),
    WM_CLIENT_STATE_FOCUS      = (1 << 7),
    WM_CLIENT_STATE_MAPPED     = (1 << 8),
    WM_CLIENT_STATE_MANAGED    = (1 << 9),
    WM_CLIENT_STATE_DESTROYING = (1 << 10)
} WmClientState;

/*==============================================================================
 * Client Window Type
 *============================================================================*/

typedef enum {
    WM_CLIENT_TYPE_UNKNOWN = 0,
    WM_CLIENT_TYPE_NORMAL,
    WM_CLIENT_TYPE_DIALOG,
    WM_CLIENT_TYPE_DOCK,
    WM_CLIENT_TYPE_DESKTOP,
    WM_CLIENT_TYPE_TOOLBAR,
    WM_CLIENT_TYPE_MENU,
    WM_CLIENT_TYPE_UTILITY,
    WM_CLIENT_TYPE_SPLASH,
    WM_CLIENT_TYPE_NOTIFICATION
} WmClientType;

/*==============================================================================
 * Client Lifecycle
 *============================================================================*/

/**
 * Create an abstract client from a native window handle.
 * This takes ownership of the native window.
 */
AbstractClient* wm_client_create(WmWindowHandle window, WmClientType type);

/**
 * Destroy a client and release all associated resources.
 */
void wm_client_destroy(AbstractClient *client);

/**
 * Check if a client is valid (not NULL and not being destroyed).
 */
bool wm_client_is_valid(const AbstractClient *client);

/*==============================================================================
 * Native Access (for compatibility during migration)
 *============================================================================*/

/**
 * Get the native window handle.
 * Note: This should be avoided in backend-agnostic code.
 */
WmWindowHandle wm_client_get_window(const AbstractClient *client);

/**
 * Get the native frame window handle (if reparented).
 */
WmWindowHandle wm_client_get_frame(const AbstractClient *client);

/**
 * Get the legacy Client structure.
 * Note: This is for gradual migration only.
 */
Client* wm_client_get_legacy(const AbstractClient *client);

/**
 * Create an abstract client wrapper around an existing legacy Client.
 * Note: The abstract client does NOT own the legacy client.
 */
AbstractClient* wm_client_from_legacy(Client *client);

/*==============================================================================
 * Client Identification
 *============================================================================*/

/**
 * Get the unique client ID.
 */
WmClientId wm_client_get_id(const AbstractClient *client);

/**
 * Get the client window type.
 */
WmClientType wm_client_get_type(const AbstractClient *client);

/**
 * Set the client window type.
 */
void wm_client_set_type(AbstractClient *client, WmClientType type);

/*==============================================================================
 * Client State
 *============================================================================*/

/**
 * Get the current state flags.
 */
WmClientState wm_client_get_state(const AbstractClient *client);

/**
 * Set state flags.
 */
void wm_client_set_state(AbstractClient *client, WmClientState state);

/**
 * Add state flags.
 */
void wm_client_add_state(AbstractClient *client, WmClientState state);

/**
 * Remove state flags.
 */
void wm_client_remove_state(AbstractClient *client, WmClientState state);

/**
 * Toggle state flags.
 */
void wm_client_toggle_state(AbstractClient *client, WmClientState state);

/**
 * Check if a specific state is set.
 */
bool wm_client_has_state(const AbstractClient *client, WmClientState state);

/* Convenience state checks */
static inline bool wm_client_is_floating(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_FLOATING);
}
static inline bool wm_client_is_fullscreen(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_FULLSCREEN);
}
static inline bool wm_client_is_maximized(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_MAXIMIZED);
}
static inline bool wm_client_is_minimized(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_MINIMIZED);
}
static inline bool wm_client_is_urgent(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_URGENT);
}
static inline bool wm_client_is_sticky(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_STICKY);
}
static inline bool wm_client_is_focused(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_FOCUS);
}
static inline bool wm_client_is_mapped(const AbstractClient *c) {
    return c && wm_client_has_state(c, WM_CLIENT_STATE_MAPPED);
}

/*==============================================================================
 * Client Geometry
 *============================================================================*/

/**
 * Get the client geometry (position and size).
 */
WmRect wm_client_get_geometry(const AbstractClient *client);

/**
 * Set the client geometry.
 */
void wm_client_set_geometry(AbstractClient *client, const WmRect *geometry);

/**
 * Get the client position.
 */
WmPoint wm_client_get_position(const AbstractClient *client);

/**
 * Set the client position.
 */
void wm_client_set_position(AbstractClient *client, int x, int y);

/**
 * Get the client size.
 */
WmSize wm_client_get_size(const AbstractClient *client);

/**
 * Set the client size.
 */
void wm_client_set_size(AbstractClient *client, int width, int height);

/**
 * Get the border width.
 */
int wm_client_get_border_width(const AbstractClient *client);

/**
 * Set the border width.
 */
void wm_client_set_border_width(AbstractClient *client, int width);

/**
 * Store previous geometry (for restore after maximize/fullscreen).
 */
void wm_client_save_geometry(AbstractClient *client);

/**
 * Restore previous geometry.
 */
void wm_client_restore_geometry(AbstractClient *client);

/*==============================================================================
 * Client Workspace
 *============================================================================*/

/**
 * Get the client's workspace ID.
 */
WmWorkspaceId wm_client_get_workspace(const AbstractClient *client);

/**
 * Set the client's workspace ID.
 */
void wm_client_set_workspace(AbstractClient *client, WmWorkspaceId workspace);

/**
 * Check if the client is on a specific workspace.
 */
bool wm_client_is_on_workspace(const AbstractClient *client, WmWorkspaceId workspace);

/**
 * Check if the client is visible on the current workspace.
 */
bool wm_client_is_visible_on_current(const AbstractClient *client);

/*==============================================================================
 * Client Properties
 *============================================================================*/

/**
 * Get the client title.
 * Returns a reference to the internal string (do not free).
 */
const char* wm_client_get_title(const AbstractClient *client);

/**
 * Set the client title.
 */
void wm_client_set_title(AbstractClient *client, const char *title);

/**
 * Get the client class (application class).
 */
const char* wm_client_get_class(const AbstractClient *client);

/**
 * Set the client class.
 */
void wm_client_set_class(AbstractClient *client, const char *class_name);

/**
 * Get the client instance name.
 */
const char* wm_client_get_instance(const AbstractClient *client);

/**
 * Set the client instance name.
 */
void wm_client_set_instance(AbstractClient *client, const char *instance);

/**
 * Get the client's taskbar color.
 */
WmColor wm_client_get_color(const AbstractClient *client);

/**
 * Set the client's taskbar color.
 */
void wm_client_set_color(AbstractClient *client, WmColor color);

/*==============================================================================
 * Client Actions
 *============================================================================*/

/**
 * Focus the client.
 */
void wm_client_focus(AbstractClient *client);

/**
 * Unfocus the client.
 */
void wm_client_unfocus(AbstractClient *client);

/**
 * Raise the client to the top of the stack.
 */
void wm_client_raise(AbstractClient *client);

/**
 * Lower the client to the bottom of the stack.
 */
void wm_client_lower(AbstractClient *client);

/**
 * Show/map the client window.
 */
void wm_client_show(AbstractClient *client);

/**
 * Hide/unmap the client window.
 */
void wm_client_hide(AbstractClient *client);

/**
 * Minimize the client.
 */
void wm_client_minimize(AbstractClient *client);

/**
 * Restore the client from minimized state.
 */
void wm_client_restore(AbstractClient *client);

/**
 * Close the client (politely request close).
 */
void wm_client_close(AbstractClient *client);

/**
 * Kill the client (forcefully terminate).
 */
void wm_client_kill(AbstractClient *client);

/*==============================================================================
 * Client Management
 *============================================================================*/

/**
 * Reparent the client into a frame window.
 */
void wm_client_reparent(AbstractClient *client, WmWindowHandle frame);

/**
 * Unreparent the client from its frame.
 */
void wm_client_unreparent(AbstractClient *client);

/**
 * Configure the client (apply size hints, constraints).
 */
void wm_client_configure(AbstractClient *client);

/**
 * Apply size hints to constrain width/height.
 */
void wm_client_apply_size_hints(AbstractClient *client, int *width, int *height);

/**
 * Move and resize a client.
 */
void wm_client_move_resize(AbstractClient *client, int x, int y, int width, int height);

/*==============================================================================
 * Client List Management
 *============================================================================*/

/**
 * Get the next client in the global list.
 */
AbstractClient* wm_client_get_next(const AbstractClient *client);

/**
 * Get the previous client in the global list.
 */
AbstractClient* wm_client_get_prev(const AbstractClient *client);

/**
 * Get the first client in the global list.
 */
AbstractClient* wm_client_get_first(void);

/**
 * Get the last client in the global list.
 */
AbstractClient* wm_client_get_last(void);

/**
 * Get the next client in MRU (Most Recently Used) order.
 */
AbstractClient* wm_client_get_next_mru(const AbstractClient *client);

/**
 * Get the previous client in MRU order.
 */
AbstractClient* wm_client_get_prev_mru(const AbstractClient *client);

/*==============================================================================
 * Client Lookup
 *============================================================================*/

/**
 * Find a client by its window handle.
 */
AbstractClient* wm_client_find_by_window(WmWindowHandle window);

/**
 * Find a client by its frame handle.
 */
AbstractClient* wm_client_find_by_frame(WmWindowHandle frame);

/**
 * Find a client by its ID.
 */
AbstractClient* wm_client_find_by_id(WmClientId id);

/*==============================================================================
 * Client Iteration
 *============================================================================*/

typedef bool (*WmClientForeachFunc)(AbstractClient *client, void *user_data);

/**
 * Iterate over all clients.
 */
void wm_client_foreach(WmClientForeachFunc func, void *user_data);

/**
 * Iterate over clients on a specific workspace.
 */
void wm_client_foreach_on_workspace(WmWorkspaceId workspace, 
                                     WmClientForeachFunc func, void *user_data);

/**
 * Count total clients.
 */
int wm_client_count(void);

/**
 * Count clients on a specific workspace.
 */
int wm_client_count_on_workspace(WmWorkspaceId workspace);

/*==============================================================================
 * Client Manager
 *============================================================================*/

typedef struct WmClientManager WmClientManager;

/**
 * Get the global client manager.
 */
WmClientManager* wm_client_manager_get(void);

/**
 * Initialize the client manager.
 */
bool wm_client_manager_init(void);

/**
 * Shutdown the client manager.
 */
void wm_client_manager_shutdown(void);

/**
 * Register a client with the manager.
 */
void wm_client_manager_add(WmClientManager *mgr, AbstractClient *client);

/**
 * Unregister a client from the manager.
 */
void wm_client_manager_remove(WmClientManager *mgr, AbstractClient *client);

/**
 * Move a client to the front of the MRU list.
 */
void wm_client_manager_touch(WmClientManager *mgr, AbstractClient *client);

/**
 * Get the focused client.
 */
AbstractClient* wm_client_manager_get_focused(const WmClientManager *mgr);

/**
 * Set the focused client.
 */
void wm_client_manager_set_focused(WmClientManager *mgr, AbstractClient *client);

#ifdef __cplusplus
}
#endif

#endif /* WM_CLIENT_H */
