#ifndef CHROMA_H
#define CHROMA_H

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

#include "chroma_version.h"

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

// 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;
  bool data_from_stbi; // true if data was allocated by stbi_load
  int ref_count;       // number of outputs using this image

  // Solid color support
  bool is_solid_color;       // true if this is a generated solid color
  uint32_t solid_color_rgba; // RGBA color value (native byte order)

  // Animation support (for animated GIFs)
  bool is_animated;        // true if this image has multiple frames
  int frame_count;         // number of frames
  int current_frame;       // current frame index
  long long last_frame_ms; // timestamp of last frame advance
  unsigned char **frames;  // array of frame data pointers
  int *frame_delays_ms;    // delay per frame in milliseconds
  int *frame_widths;       // width per frame
  int *frame_heights;      // height per frame
} 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;
  uint32_t configure_serial;

  // Shared memory buffer
  struct wl_buffer *shm_buffer;
  void *shm_data;
  size_t shm_size;
  int shm_stride;

  // 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;
  bool configured; // track if initial configure received

  // Transition support
  bool in_transition;             // whether crossfade transition is active
  long long transition_start_ms;  // when transition began
  unsigned char *transition_prev; // previous frame pixel data (RGBA)
  size_t transition_prev_size;    // size of previous frame data
  int transition_prev_width;      // width of previous frame
  int transition_prev_height;     // height of previous frame
  int transition_duration_ms;     // duration for this output's transition
} 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)

  // Solid color background support
  // When set via config or IPC, generates a solid color instead of loading an
  // image If non-empty, overrides image loading (format: "rrggbb" or
  // "rrggbbaa")
  char solid_color[10];

  // Transition settings
  bool transition_enabled;    // enable smooth crossfade transitions
  int transition_duration_ms; // crossfade duration in milliseconds

  // Animation settings
  bool animation_enabled; // enable animated GIF playback
  int animation_max_fps;  // max frames per second for animations

  // IPC settings
  bool ipc_enabled;                   // enable IPC command socket
  char ipc_socket_path[MAX_PATH_LEN]; // path to Unix domain socket
} 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;
  struct wl_shm *shm;

  // 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;

  // IPC
  int ipc_fd;                     // IPC socket file descriptor
  char config_file[MAX_PATH_LEN]; // active config file path

  // Animation timing
  long long last_anim_ms; // timestamp of last animation frame advance
} chroma_state_t;

// 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 methods
int32_t chroma_output_width(chroma_output_t* output);
int32_t chroma_output_height(chroma_output_t* output);

// 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);


// Rendering and surface management
int chroma_surface_create(chroma_state_t *state, chroma_output_t *output);
void chroma_surface_destroy(chroma_output_t *output);
int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output);
void chroma_buffer_destroy(chroma_output_t *output);
void chroma_buffer_unmap(chroma_output_t *output);
int chroma_render_wallpaper(chroma_state_t *state, 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, int output_width,
                      int output_height);
void chroma_image_free(chroma_image_t *image);
void chroma_image_release(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 output_width,
                                         int output_height);
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);

// Solid color image generation
int chroma_image_load_color(chroma_image_t *image, uint32_t color_rgba,
                            int width, int height);

// Additional image format loaders
int chroma_image_load_farbfeld(chroma_image_t *image, const char *path);
int chroma_image_load_svg(chroma_image_t *image, const char *path,
                          int out_width, int out_height);
int chroma_image_load_webp(chroma_image_t *image, const char *path);
int chroma_image_load_tiff(chroma_image_t *image, const char *path);
int chroma_image_load_avif(chroma_image_t *image, const char *path);
int chroma_image_load_jpegxl(chroma_image_t *image, const char *path);

// Animation functions
int chroma_anim_load_gif(chroma_image_t *image, const char *path);
void chroma_anim_advance_frame(chroma_image_t *image,
                               long long current_time_ms);
void chroma_anim_free_frames(chroma_image_t *image);
bool chroma_anim_needs_redraw(chroma_state_t *state);
int chroma_anim_update_outputs(chroma_state_t *state);

// Transition functions
void chroma_transition_init_output(chroma_output_t *output, int duration_ms);
void chroma_transition_cleanup_output(chroma_output_t *output);
bool chroma_transition_is_active(chroma_output_t *output);
float chroma_transition_get_alpha(chroma_output_t *output,
                                  long long current_time_ms);
bool chroma_transition_needs_redraw(chroma_state_t *state);
int chroma_transition_update_outputs(chroma_state_t *state);

// IPC functions
int chroma_ipc_init(chroma_state_t *state);
void chroma_ipc_cleanup(chroma_state_t *state);
int chroma_ipc_process(chroma_state_t *state);
int chroma_ipc_get_fd(chroma_state_t *state);

// Configuration
int chroma_config_load(chroma_config_t *config, const char *config_file);
int chroma_config_load_toml(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,
                                               const char *output_description);
int chroma_config_get_mapping_for_output(
    chroma_config_t *config, const char *output_name,
    const char *output_description, 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);

// Runtime wallpaper control
int chroma_set_wallpaper_for_output(chroma_state_t *state,
                                    const char *output_name,
                                    const char *image_path);
int chroma_set_wallpaper_for_all(chroma_state_t *state, const char *image_path);
int chroma_set_solid_color_for_output(chroma_state_t *state,
                                      const char *output_name,
                                      const char *hex_color);
int chroma_set_solid_color_for_all(chroma_state_t *state,
                                   const char *hex_color);

// 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);
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
