#ifndef CHROMA_H
#define CHROMA_H

#include "wlr-layer-shell-unstable-v1.h"
#include "xdg-shell.h"
#include <EGL/egl.h>
#include <GL/gl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <wayland-client.h>
#include <wayland-egl.h>

#include "chroma_version.h"

#define MAX_OUTPUTS 16
#define MAX_PATH_LEN 4096
#define CONFIG_FILE_NAME "chroma.conf"

// Log levels
#define CHROMA_LOG_ERROR 0
#define CHROMA_LOG_WARN 1
#define CHROMA_LOG_INFO 2
#define CHROMA_LOG_DEBUG 3
#define CHROMA_LOG_TRACE 4

// Error codes
typedef enum {
  CHROMA_OK = 0,
  CHROMA_ERROR_INIT = -1,
  CHROMA_ERROR_WAYLAND = -2,
  CHROMA_ERROR_EGL = -3,
  CHROMA_ERROR_IMAGE = -4,
  CHROMA_ERROR_CONFIG = -5,
  CHROMA_ERROR_MEMORY = -6
} chroma_error_t;

// Scaling modes for wallpaper display
typedef enum {
  CHROMA_SCALE_FILL = 0,    // fill entire output, crop if necessary
  CHROMA_SCALE_FIT = 1,     // fit image within output, add borders if needed
  CHROMA_SCALE_STRETCH = 2, // stretch to fill output, may distort aspect ratio
  CHROMA_SCALE_CENTER = 3   // center image at original size
} chroma_scale_mode_t;

// Anchor positions for wallpaper placement
typedef enum {
  CHROMA_ANCHOR_CENTER = 0,      // center of the output (default)
  CHROMA_ANCHOR_TOP = 1,         // top edge, centered horizontally
  CHROMA_ANCHOR_BOTTOM = 2,      // bottom edge, centered horizontally
  CHROMA_ANCHOR_LEFT = 3,        // left edge, centered vertically
  CHROMA_ANCHOR_RIGHT = 4,       // right edge, centered vertically
  CHROMA_ANCHOR_TOP_LEFT = 5,    // top-left corner
  CHROMA_ANCHOR_TOP_RIGHT = 6,   // top-right corner
  CHROMA_ANCHOR_BOTTOM_LEFT = 7, // bottom-left corner
  CHROMA_ANCHOR_BOTTOM_RIGHT = 8 // bottom-right corner
} chroma_anchor_t;

// Image filtering quality settings
typedef enum {
  CHROMA_FILTER_NEAREST = 0,  // nearest neighbor filtering (pixelated)
  CHROMA_FILTER_LINEAR = 1,   // linear filtering (smooth)
  CHROMA_FILTER_BILINEAR = 2, // bilinear filtering (smoother)
  CHROMA_FILTER_TRILINEAR = 3 // trilinear filtering (smoothest)
} chroma_filter_quality_t;

// Image data structure
typedef struct {
  unsigned char *data; // RGBA pixel data
  int width;
  int height;
  int channels;
  char path[MAX_PATH_LEN];
  bool loaded;
} chroma_image_t;

// Wayland output information
typedef struct {
  struct wl_output *wl_output;
  uint32_t id;
  int32_t x, y;
  int32_t width, height;
  int32_t scale;
  enum wl_output_transform transform;
  char *name;
  char *description;
  bool active;

  // Back reference to state
  struct chroma_state *state;

  // Rendering context
  struct wl_surface *surface;
  struct zwlr_layer_surface_v1 *layer_surface;
  struct wl_egl_window *egl_window;
  EGLSurface egl_surface;
  uint32_t configure_serial;

  // Associated wallpaper
  chroma_image_t *image;

  // Configuration for this output
  chroma_scale_mode_t scale_mode;
  chroma_filter_quality_t filter_quality;
  chroma_anchor_t anchor;
  float anchor_x; // custom X offset (0-100, 50=center)
  float anchor_y; // custom Y offset (0-100, 50=center)
  bool config_loaded;

  // OpenGL resource cache
  GLuint texture_id;
  GLuint shader_program;
  GLuint vbo;
  GLuint ebo;
  bool gl_resources_initialized;
  bool texture_uploaded;
  bool vbo_dirty; // track VBO needs update
} chroma_output_t;

// Config mapping structure
typedef struct {
  char output_name[256];
  char image_path[MAX_PATH_LEN];
  chroma_scale_mode_t scale_mode;
  chroma_filter_quality_t filter_quality;
  chroma_anchor_t anchor;
  float anchor_x; // custom X offset (0-100, 50=center, 0=left, 100=right)
  float anchor_y; // custom Y offset (0-100, 50=center, 0=top, 100=bottom)
} chroma_config_mapping_t;

// Application configuration
typedef struct {
  chroma_config_mapping_t mappings[MAX_OUTPUTS];
  int mapping_count;
  char default_image[MAX_PATH_LEN];
  bool daemon_mode;

  // Global scaling and filtering settings (used as defaults)
  chroma_scale_mode_t default_scale_mode;
  chroma_filter_quality_t default_filter_quality;
  chroma_anchor_t default_anchor;
  float default_anchor_x; // custom anchor X offset (0-100, 50=center)
  float default_anchor_y; // custom anchor Y offset (0-100, 50=center)

  // Image downsampling settings
  bool enable_downsampling; // enable automatic downsampling
  int max_output_width;     // maximum expected output width
  int max_output_height;    // maximum expected output height
  float min_scale_factor;   // minimum scale factor (don't scale below this)
} chroma_config_t;

// Main application state
typedef struct chroma_state {
  // Wayland globals
  struct wl_display *display;
  struct wl_registry *registry;
  struct wl_compositor *compositor;
  struct zwlr_layer_shell_v1 *layer_shell;

  // EGL context
  EGLDisplay egl_display;
  EGLContext egl_context;
  EGLConfig egl_config;

  // Outputs
  chroma_output_t outputs[MAX_OUTPUTS];
  int output_count;

  // Images
  chroma_image_t images[MAX_OUTPUTS];
  int image_count;

  // Configuration
  chroma_config_t config;

  // State flags
  bool running;
  bool initialized;
} chroma_state_t;

// Function declarations

// Initialization and cleanup
int chroma_init(chroma_state_t *state);
void chroma_cleanup(chroma_state_t *state);

// Wayland management
int chroma_wayland_connect(chroma_state_t *state);
void chroma_wayland_disconnect(chroma_state_t *state);
void chroma_registry_listener(void *data, struct wl_registry *registry,
                              uint32_t id, const char *interface,
                              uint32_t version);
void chroma_registry_remove(void *data, struct wl_registry *registry,
                            uint32_t id);

// Output management
int chroma_output_add(chroma_state_t *state, uint32_t id,
                      struct wl_output *output);
void chroma_output_remove(chroma_state_t *state, uint32_t id);
chroma_output_t *chroma_output_find_by_id(chroma_state_t *state, uint32_t id);
chroma_output_t *chroma_output_find_by_name(chroma_state_t *state,
                                            const char *name);

// Output event handlers
void chroma_output_geometry(void *data, struct wl_output *output, int32_t x,
                            int32_t y, int32_t physical_width,
                            int32_t physical_height, int32_t subpixel,
                            const char *make, const char *model,
                            int32_t transform);
void chroma_output_mode(void *data, struct wl_output *output, uint32_t flags,
                        int32_t width, int32_t height, int32_t refresh);
void chroma_output_scale(void *data, struct wl_output *output, int32_t scale);
void chroma_output_name(void *data, struct wl_output *output, const char *name);
void chroma_output_description(void *data, struct wl_output *output,
                               const char *description);
void chroma_output_done(void *data, struct wl_output *output);

// EGL and rendering
int chroma_egl_init(chroma_state_t *state);
void chroma_egl_cleanup(chroma_state_t *state);
int chroma_surface_create(chroma_state_t *state, chroma_output_t *output);
void chroma_surface_destroy(chroma_output_t *output);
int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output);
void chroma_output_invalidate_texture(chroma_output_t *output);

// Layer shell functions
void chroma_layer_surface_configure(void *data,
                                    struct zwlr_layer_surface_v1 *layer_surface,
                                    uint32_t serial, uint32_t width,
                                    uint32_t height);
void chroma_layer_surface_closed(void *data,
                                 struct zwlr_layer_surface_v1 *layer_surface);

// Image loading
void chroma_image_init_stb(void);
int chroma_image_load(chroma_image_t *image, const char *path,
                      const chroma_config_t *config);
void chroma_image_free(chroma_image_t *image);
chroma_image_t *chroma_image_find_by_path(chroma_state_t *state,
                                          const char *path);
chroma_image_t *chroma_image_get_or_load(chroma_state_t *state,
                                         const char *path);
int chroma_image_validate(const char *path);
int chroma_image_get_info(const char *path, int *width, int *height,
                          int *channels);
void chroma_images_cleanup(chroma_state_t *state);

// Configuration
int chroma_config_load(chroma_config_t *config, const char *config_file);
void chroma_config_free(chroma_config_t *config);
const char *chroma_config_get_image_for_output(chroma_config_t *config,
                                               const char *output_name);
int chroma_config_get_mapping_for_output(
    chroma_config_t *config, const char *output_name,
    chroma_scale_mode_t *scale_mode, chroma_filter_quality_t *filter_quality,
    chroma_anchor_t *anchor, float *anchor_x, float *anchor_y);

void chroma_config_print(const chroma_config_t *config);

// Main loop and events
int chroma_run(chroma_state_t *state);
void chroma_handle_signals(void);
int chroma_reload_config(chroma_state_t *state, const char *config_file);
int chroma_update_outputs(chroma_state_t *state);
void chroma_get_stats(chroma_state_t *state, int *active_outputs,
                      int *loaded_images);
void handle_output_done(chroma_state_t *state, chroma_output_t *output);

// Utilities
void chroma_log(const char *level, const char *format, ...);
const char *chroma_error_string(chroma_error_t error);
void chroma_set_log_level(int level);
int chroma_get_log_level(void);
void chroma_set_signal_state(chroma_state_t *state, const char *config_file);
void chroma_cleanup_signals(void);
char *chroma_expand_path(const char *path);
int chroma_mkdir_recursive(const char *path, mode_t mode);
char *chroma_get_config_dir(void);
bool chroma_path_exists(const char *path);
bool chroma_is_regular_file(const char *path);
bool chroma_is_directory(const char *path);
long chroma_get_file_size(const char *path);
const char *chroma_get_file_extension(const char *path);
int chroma_strcasecmp(const char *s1, const char *s2);
size_t chroma_strlcpy(char *dst, const char *src, size_t size);
size_t chroma_strlcat(char *dst, const char *src, size_t size);
long long chroma_get_time_ms(void);
void chroma_sleep_ms(long ms);
void chroma_format_memory_size(size_t bytes, char *buffer, size_t buffer_size);
void chroma_utils_cleanup(void);

// Memory tracking and logging
void chroma_log_memory_stats(const char *context);
size_t chroma_get_memory_usage(void);
void chroma_log_resource_allocation(const char *resource_type, size_t size,
                                    const char *description);
void chroma_log_resource_deallocation(const char *resource_type, size_t size,
                                      const char *description);

// Listener structures
extern const struct wl_registry_listener chroma_registry_listener_impl;
extern const struct wl_output_listener chroma_output_listener_impl;
extern const struct zwlr_layer_surface_v1_listener
    chroma_layer_surface_listener_impl;

// Global state for signal handling
extern volatile sig_atomic_t chroma_should_quit;

#endif // CHROMA_H
