#pragma once

#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include <time.h>

#define SXBAR_VERSION	"sxbar ver. 1.1"
#define SXBAR_AUTHOR	"(C) Abhinav Prasai 2025"
#define SXBAR_LICINFO	"See LICENSE for more info"

#define MAX_MONITORS 32

/* module horizontal alignment groups -- RIGHT is 0 so existing configs
 * (which never set align) keep today's right-anchored-cluster behaviour */
#define ALIGN_RIGHT  0
#define ALIGN_LEFT   1
#define ALIGN_CENTER 2

/* whether a module has a popup at all: NONE is 0 so existing configs
 * (which never set popup) keep today's plain click/scroll behaviour with
 * no floating window. A popup is a list of rows (PopupItem), each with
 * its own POPUP_ROW_* type -- text, button and slider rows can all be
 * mixed freely in the same popup. */
#define POPUP_NONE    0
#define POPUP_BUTTONS 1

#define POPUP_TRIGGER_CLICK 0
#define POPUP_TRIGGER_HOVER 1

#define POPUP_ROW_TEXT    0 /* purely informational -- not clickable at all */
#define POPUP_ROW_BUTTON  1 /* spawns command; popup stays open on click */
#define POPUP_ROW_SLIDER  2 /* draggable 0-100% track; doesn't close on click/drag */
#define POPUP_ROW_IMAGE   3 /* renders an image file (e.g. album art); not clickable */
#define POPUP_ROW_BUTTONS 4 /* one row split into N equal-width button segments,
                             * e.g. media transport controls (prev/play/next) */

/* one segment of a POPUP_ROW_BUTTONS row -- same label/command shape as a
 * plain POPUP_ROW_BUTTON, just laid out side by side instead of stacked */
typedef struct PopupButton {
	char *label;
	char *command;
} PopupButton;

/* one row of a popup. label_command, if set, is re-run fresh (via
 * run_command()) every time the popup opens instead of using a fixed
 * label -- used by TEXT and BUTTON rows for live status text (label
 * itself is then overwritten in place and freed/reused across opens). A
 * SLIDER row instead seeds its value from the module's own command
 * output, and set_command receives the new value as $1 when dragged. An
 * IMAGE row's image_command is re-run the same way as label_command, but
 * its output is a path to a local image file (or empty for "no image
 * this time"); `image` is the XImage decoded (via vendored stb_image.h)
 * and scaled from that path by the most recent popup_open() (opaque here
 * -- only sxbar.c touches it directly), sized image_w x image_h. A
 * BUTTONS row's `buttons`/`button_count` hold its segments; labels are
 * static (no per-segment label_command). A TEXT/BUTTON row whose label
 * doesn't fit the popup's width (e.g. the popup's width came from an
 * IMAGE/SLIDER/BUTTONS row instead of growing to fit this text) scrolls
 * within it instead, using its own scroll_offset -- same marquee scheme
 * as a bar module's max_width, just scoped to one popup row. */
typedef struct PopupItem {
	int type;
	char *label;
	char *command;
	char *label_command;
	char *set_command;
	char *image_command;
	void *image;
	int image_w, image_h;
	PopupButton *buttons;
	int button_count;
	int scroll_offset; /* TEXT/BUTTON: marquee position, in pixels */
	int value;         /* SLIDER: current 0-100 */
	int last_spawned;  /* SLIDER: last value set_command was actually run for */
} PopupItem;

/* one window entry in the built-in `taskbar` module -- see
 * update_taskbar() (src/sxbar.c) for how these get populated from
 * scripts/taskbar.sh's internal listing format, and id's role in
 * highlighting whichever entry is the current _NET_ACTIVE_WINDOW */
typedef struct TaskbarEntry {
	char *label;   /* window title */
	char *command; /* spawned on click, e.g. "taskbar.sh focus 0x0140..." */
	Window id;
	int monitor;   /* which monitor (index into monitors[]) the script placed
	               * this window on, or -1 if the script didn't say -- see
	               * update_taskbar()'s geometry args and taskbar.sh's
	               * `list` case, which does the actual window-to-monitor
	               * matching in awk */
} TaskbarEntry;

typedef struct Module {
	char *name;
	char *command;
	char *click_command;
	char *scroll_up_command;
	char *scroll_down_command;
	char *colour;
	char *prefix;
	char *prefix_command;
	char *prefix_cached;
	int min_width;
	int max_width;    /* 0 = no cap; text wider than this scrolls (marquee)
	                   * instead of stretching the bar -- see max_width in
	                   * sxbarc */
	int scroll_offset; /* marquee: current scroll position, in pixels */
	int on_secondary;
	int align;
	int icon_only; /* show only the prefix/icon, never the module's own text */
	XftColor xft_colour;
	int has_colour;
	int enabled;
	int refresh_interval;
	time_t last_update;
	char *cached_output;
	/* floating popup window opened on hover or click */
	int popup_type;
	int popup_trigger;
	PopupItem *popup_items;
	int popup_item_count;
	int popup_item_max;
	int popup_image_size; /* IMAGE rows scale to fit within this square box,
	                       * in pixels; 0 = built-in default (see
	                       * POPUP_IMAGE_SIZE in sxbar.c) */
	int popup_items_from_config; /* config popup_item/popup_info lines replace the built-in defaults, once */
	int slider_item_idx;          /* which popup_items[] entry popup_set manages, or -1 */
	/* the built-in `taskbar` module only: renders one clickable segment
	 * per current-workspace window directly in the bar itself, instead
	 * of a single cached_output string -- see update_taskbar() and the
	 * dedicated block in draw_bar_into() (src/sxbar.c) */
	TaskbarEntry *taskbar_entries;
	int taskbar_entry_count;
} Module;

/* maps a workspace's displayed label -- its _NET_DESKTOP_NAMES string,
 * e.g. "1" -- to replacement text, e.g. a Nerd Font glyph, via the
 * `workspace_icon` config directive */
typedef struct WorkspaceIcon {
	char *name;
	char *icon;
} WorkspaceIcon;

typedef struct Config {
	int bottom_bar;
	int height;
	int vertical_padding;
	int horizontal_padding;
	int text_padding;
	int border;
	int border_width;
	unsigned long background_colour;
	unsigned long foreground_colour;
	unsigned long border_colour;
	char *font;
	int show_version;
	char *version_text;
	Module *modules;
	int module_count;
	int max_modules;
	int secondary_bar;
	WorkspaceIcon *workspace_icons;
	int workspace_icon_count;
	int workspace_icon_max;
} Config;

/* one on-screen bar window: either the primary bar (workspaces + all
 * primary-tagged modules + version) or the secondary bar (modules tagged
 * `bar : module_name : secondary` only, on the opposite edge) */
typedef struct Bar {
	int monitor;
	int is_secondary;
	Window win;
	Pixmap buffer;
	XftDraw *xft_draw;
} Bar;

/* the single floating popup window (at most one open at a time) */
typedef struct Popup {
	int open;
	Window win;
	Pixmap buffer;
	XftDraw *xft_draw;
	Module *module;
	int bar_idx;
	int trigger;
	int x, y, w, h;
	int hover_row;    /* row index highlighted (BUTTON/BUTTONS rows only), or -1 */
	int hover_col;    /* BUTTONS row: which segment is highlighted, or -1 */
	int dragging_row; /* row index of the SLIDER row being dragged, or -1 */
} Popup;

typedef void (*EventHandler)(XEvent *);
