/*
 * Nuklear GLFW3 Demo Application - Modular UI Components
 * A simple desktop GUI application using GLFW3 and Nuklear with modular component architecture
 * 
 * MODULAR COMPONENT STRUCTURE:
 * 
 * This application demonstrates a clean, modular approach to UI component organization:
 * 
 * 1. UI STATE MANAGEMENT:
 *    - Centralized state in ui_state_t structure
 *    - Clean separation between UI rendering and state management
 *    - Easy state reset and manipulation functions
 * 
 * 2. COMPONENT INTERFACE:
 *    - Each UI component is a function with signature: void render_*_component(nk_context*, ui_state_t*)
 *    - Components are registered in ui_components[] array
 *    - Components can be enabled/disabled individually
 *    - Easy to add new components by implementing the interface and adding to registry
 * 
 * 3. CLEAN SEPARATION:
 *    - GLFW window management is separate from UI rendering
 *    - Nuklear integration is isolated in init/cleanup functions
 *    - Application logic is separated from rendering logic
 * 
 * 4. EXTENSIBILITY:
 *    - Adding new components requires: implement render function + add to registry
 *    - State management is centralized and easily extensible
 *    - Component enable/disable functionality built-in
 * 
 * HOW TO ADD NEW COMPONENTS:
 * 1. Add state variables to ui_state_t if needed
 * 2. Implement render_*_component(ctx, state) function
 * 3. Add component to ui_components[] array
 * 4. Optionally add state management functions
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GL/gl3w.h>

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_GLFW_GL3_IMPLEMENTATION
#define NK_KEYSTATE_BASED_INPUT
#include "nuklear.h"
#include "nuklear_glfw_gl3.h"

// Window dimensions
static int window_width = 800;
static int window_height = 600;
static int min_window_width = 400;
static int min_window_height = 300;
static GLFWwindow* window = NULL;

// Nuklear context
static struct nk_context* ctx = NULL;
static struct nk_glfw glfw = {0};

// Nuklear rendering constants
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024

// =============================================================================
// UI COMPONENT STATE MANAGEMENT
// =============================================================================

// UI Component State Structure
typedef struct {
    // Text input component state
    char text_buffer[256];
    
    // Slider component state
    float slider_value;
    
    // Checkbox component state
    int checkbox_value;
    
    // Radio button component state
    int option_selected;
    
    // Button component state
    int button_click_count;
    
    // Window information state
    char status_message[512];
} ui_state_t;

// Global UI state instance
static ui_state_t ui_state = {
    .text_buffer = "Hello World!",
    .slider_value = 0.5f,
    .checkbox_value = 1,
    .option_selected = 0,
    .button_click_count = 0,
    .status_message = "Application started"
};

// =============================================================================
// UI COMPONENT INTERFACE DEFINITIONS
// =============================================================================

// UI Component rendering function type
typedef void (*ui_component_render_fn)(struct nk_context* ctx, ui_state_t* state);

// UI Component structure
typedef struct {
    const char* name;
    ui_component_render_fn render;
    int enabled;
} ui_component_t;

// =============================================================================
// FORWARD DECLARATIONS
// =============================================================================

// Core application functions
void init_glfw(void);
void init_nuklear(void);
void render_ui(struct nk_context* ctx);
void cleanup(void);

// Window management callbacks
void window_size_callback(GLFWwindow* window, int width, int height);
void window_iconify_callback(GLFWwindow* window, int iconified);
void window_maximize_callback(GLFWwindow* window, int maximized);
void error_callback(int error, const char* description);

// UI utility functions
float get_ui_scale_factor(void);
struct nk_rect get_scaled_window_rect(void);

// UI Component rendering functions
void render_window_info_component(struct nk_context* ctx, ui_state_t* state);
void render_button_component(struct nk_context* ctx, ui_state_t* state);
void render_text_input_component(struct nk_context* ctx, ui_state_t* state);
void render_slider_component(struct nk_context* ctx, ui_state_t* state);
void render_checkbox_component(struct nk_context* ctx, ui_state_t* state);
void render_radio_button_component(struct nk_context* ctx, ui_state_t* state);
void render_status_component(struct nk_context* ctx, ui_state_t* state);

// UI state management functions
void ui_state_update_status(const char* message);
void ui_state_reset(void);

// UI component management functions
void ui_component_set_enabled(const char* component_name, int enabled);
int ui_component_is_enabled(const char* component_name);

// Error callback for GLFW
void error_callback(int error, const char* description) {
    fprintf(stderr, "GLFW Error %d: %s\n", error, description);
}

// Window resize callback
void window_size_callback(GLFWwindow* window, int width, int height) {
    // Enforce minimum window size constraints
    if (width < min_window_width || height < min_window_height) {
        int new_width = width < min_window_width ? min_window_width : width;
        int new_height = height < min_window_height ? min_window_height : height;
        glfwSetWindowSize(window, new_width, new_height);
        return;
    }
    
    window_width = width;
    window_height = height;
    glViewport(0, 0, width, height);
    
    printf("Window resized to: %dx%d\n", width, height);
}

// Window iconify (minimize) callback
void window_iconify_callback(GLFWwindow* window, int iconified) {
    if (iconified) {
        printf("Window minimized\n");
    } else {
        printf("Window restored from minimized state\n");
    }
}

// Window maximize callback
void window_maximize_callback(GLFWwindow* window, int maximized) {
    if (maximized) {
        printf("Window maximized\n");
    } else {
        printf("Window restored from maximized state\n");
    }
}

// Calculate UI scale factor based on window size
float get_ui_scale_factor(void) {
    // Base scale factor on window width, with minimum scale of 0.8 and maximum of 2.0
    float base_width = 800.0f;
    float scale = (float)window_width / base_width;
    
    // Clamp scale factor to reasonable bounds
    if (scale < 0.8f) scale = 0.8f;
    if (scale > 2.0f) scale = 2.0f;
    
    return scale;
}

// Get scaled window rectangle for responsive UI layout
struct nk_rect get_scaled_window_rect(void) {
    float scale = get_ui_scale_factor();
    
    // Calculate responsive window position and size
    float base_x = 50.0f;
    float base_y = 50.0f;
    float base_width = 400.0f;
    float base_height = 500.0f;
    
    // Scale the window dimensions but keep it within screen bounds
    float scaled_width = base_width * scale;
    float scaled_height = base_height * scale;
    
    // Ensure the window fits within the screen
    if (scaled_width > window_width - 100) {
        scaled_width = window_width - 100;
    }
    if (scaled_height > window_height - 100) {
        scaled_height = window_height - 100;
    }
    
    // Center the window if it's getting too large
    float x = base_x;
    float y = base_y;
    if (scaled_width > base_width * 1.5f) {
        x = (window_width - scaled_width) / 2.0f;
    }
    if (scaled_height > base_height * 1.5f) {
        y = (window_height - scaled_height) / 2.0f;
    }
    
    return nk_rect(x, y, scaled_width, scaled_height);
}

// Initialize GLFW and create window
void init_glfw(void) {
    // Set error callback
    glfwSetErrorCallback(error_callback);
    
    // Initialize GLFW
    if (!glfwInit()) {
        fprintf(stderr, "Failed to initialize GLFW\n");
        exit(EXIT_FAILURE);
    }
    
    // Set OpenGL version to 3.3 core profile
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    
    // Create window
    window = glfwCreateWindow(window_width, window_height, "Nuklear GLFW3 Demo", NULL, NULL);
    if (!window) {
        fprintf(stderr, "Failed to create GLFW window\n");
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    
    // Make the window's context current
    glfwMakeContextCurrent(window);
    
    // Initialize OpenGL loader (gl3w)
    if (gl3wInit() != 0) {
        fprintf(stderr, "Failed to initialize OpenGL loader\n");
        glfwDestroyWindow(window);
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    
    // Set window size limits
    glfwSetWindowSizeLimits(window, min_window_width, min_window_height, GLFW_DONT_CARE, GLFW_DONT_CARE);
    
    // Set callbacks
    glfwSetWindowSizeCallback(window, window_size_callback);
    glfwSetWindowIconifyCallback(window, window_iconify_callback);
    glfwSetWindowMaximizeCallback(window, window_maximize_callback);
    
    // Enable vsync
    glfwSwapInterval(1);
    
    // Set initial viewport
    glViewport(0, 0, window_width, window_height);
    
    printf("GLFW initialized successfully\n");
    printf("OpenGL Version: %s\n", glGetString(GL_VERSION));
    printf("Window size limits set to: %dx%d minimum\n", min_window_width, min_window_height);
    printf("Initial window size: %dx%d\n", window_width, window_height);
}

// Initialize Nuklear with GLFW+OpenGL3 backend
void init_nuklear(void) {
    // Initialize Nuklear context with GLFW+OpenGL3 backend
    ctx = nk_glfw3_init(&glfw, window, NK_GLFW3_INSTALL_CALLBACKS);
    if (!ctx) {
        fprintf(stderr, "Failed to initialize Nuklear context\n");
        cleanup();
        exit(EXIT_FAILURE);
    }
    
    // Load default font
    struct nk_font_atlas *atlas;
    nk_glfw3_font_stash_begin(&glfw, &atlas);
    nk_glfw3_font_stash_end(&glfw);
    
    printf("Nuklear initialized successfully\n");
    
    // Test minimum window size constraint
    printf("Testing minimum window size constraint...\n");
    glfwSetWindowSize(window, 200, 150); // Try to set below minimum
    glfwPollEvents(); // Process the resize event
    
    int test_width, test_height;
    glfwGetWindowSize(window, &test_width, &test_height);
    printf("Attempted to set window to 200x150, actual size: %dx%d\n", test_width, test_height);
    
    // Reset to normal size
    glfwSetWindowSize(window, window_width, window_height);
}

// =============================================================================
// UI COMPONENT REGISTRY
// =============================================================================

// Define all available UI components
static ui_component_t ui_components[] = {
    {"Window Info", render_window_info_component, 1},
    {"Buttons", render_button_component, 1},
    {"Text Input", render_text_input_component, 1},
    {"Slider", render_slider_component, 1},
    {"Checkbox", render_checkbox_component, 1},
    {"Radio Buttons", render_radio_button_component, 1},
    {"Status", render_status_component, 1}
};

#define UI_COMPONENT_COUNT (sizeof(ui_components) / sizeof(ui_components[0]))

// =============================================================================
// MAIN UI RENDERING FUNCTION
// =============================================================================

// Render main UI using modular component system
void render_ui(struct nk_context* ctx) {
    // Get responsive window rectangle
    struct nk_rect window_rect = get_scaled_window_rect();
    
    // Main demo window with title bar showing application name and current window size
    char window_title[256];
    snprintf(window_title, sizeof(window_title), 
             "Nuklear GLFW3 Demo - Modular UI Components [%dx%d]", 
             window_width, window_height);
    
    if (nk_begin(ctx, window_title, window_rect,
                 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
                 NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) {
        
        // Render all enabled UI components
        for (int i = 0; i < UI_COMPONENT_COUNT; i++) {
            if (ui_components[i].enabled && ui_components[i].render) {
                ui_components[i].render(ctx, &ui_state);
                
                // Add separator between components (except for the last one)
                if (i < UI_COMPONENT_COUNT - 1) {
                    nk_layout_row_dynamic(ctx, 10, 1);
                    nk_spacing(ctx, 1);
                }
            }
        }
    }
    nk_end(ctx);
}

// =============================================================================
// UI COMPONENT IMPLEMENTATIONS
// =============================================================================

// Window information component
void render_window_info_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float label_height = 25.0f * scale;
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Window Information:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "Window Size: %dx%d", window_width, window_height);
    nk_labelf(ctx, NK_TEXT_LEFT, "UI Scale Factor: %.2f", scale);
}

// Button component with click tracking
void render_button_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float button_height = 30.0f * scale;
    float label_height = 25.0f * scale;
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Button Examples:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, button_height, 2);
    if (nk_button_label(ctx, "Click Me")) {
        state->button_click_count++;
        snprintf(state->status_message, sizeof(state->status_message), 
                "Standard button clicked! Count: %d (Scale: %.2f)", 
                state->button_click_count, scale);
        printf("%s\n", state->status_message);
    }
    
    if (nk_button_label(ctx, "Action Button")) {
        state->button_click_count++;
        snprintf(state->status_message, sizeof(state->status_message), 
                "Action button pressed! Count: %d (Scale: %.2f)", 
                state->button_click_count, scale);
        printf("%s\n", state->status_message);
    }
    
    nk_layout_row_dynamic(ctx, button_height, 1);
    if (nk_button_label(ctx, "Wide Button")) {
        state->button_click_count++;
        snprintf(state->status_message, sizeof(state->status_message), 
                "Wide button activated! Count: %d (Scale: %.2f)", 
                state->button_click_count, scale);
        printf("%s\n", state->status_message);
    }
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "Total button clicks: %d", state->button_click_count);
}

// Text input component
void render_text_input_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float label_height = 25.0f * scale;
    float input_height = 30.0f * scale;
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Text Input Example:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Enter text below:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, input_height, 1);
    nk_edit_string_zero_terminated(ctx, NK_EDIT_FIELD, state->text_buffer, 
                                  sizeof(state->text_buffer), nk_filter_default);
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "You typed: %s", state->text_buffer);
}

// Slider component
void render_slider_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float label_height = 25.0f * scale;
    float widget_height = 30.0f * scale;
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Slider Control:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, widget_height, 1);
    float old_value = state->slider_value;
    state->slider_value = nk_slide_float(ctx, 0.0f, state->slider_value, 1.0f, 0.01f);
    
    // Update status when slider value changes
    if (old_value != state->slider_value) {
        snprintf(state->status_message, sizeof(state->status_message), 
                "Slider value changed to: %.2f", state->slider_value);
    }
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "Slider value: %.2f", state->slider_value);
}

// Checkbox component
void render_checkbox_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float label_height = 25.0f * scale;
    float widget_height = 30.0f * scale;
    
    nk_layout_row_dynamic(ctx, widget_height, 1);
    int old_value = state->checkbox_value;
    state->checkbox_value = nk_check_label(ctx, "Enable feature", state->checkbox_value);
    
    // Update status when checkbox value changes
    if (old_value != state->checkbox_value) {
        snprintf(state->status_message, sizeof(state->status_message), 
                "Feature %s", state->checkbox_value ? "enabled" : "disabled");
    }
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "Checkbox is: %s", 
             state->checkbox_value ? "Checked" : "Unchecked");
}

// Radio button component
void render_radio_button_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float label_height = 25.0f * scale;
    float widget_height = 30.0f * scale;
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Radio Button Options:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, widget_height, 1);
    if (nk_option_label(ctx, "Option A", state->option_selected == 0)) {
        if (state->option_selected != 0) {
            state->option_selected = 0;
            snprintf(state->status_message, sizeof(state->status_message), 
                    "Selected Option A (Scale: %.2f)", scale);
            printf("%s\n", state->status_message);
        }
    }
    
    nk_layout_row_dynamic(ctx, widget_height, 1);
    if (nk_option_label(ctx, "Option B", state->option_selected == 1)) {
        if (state->option_selected != 1) {
            state->option_selected = 1;
            snprintf(state->status_message, sizeof(state->status_message), 
                    "Selected Option B (Scale: %.2f)", scale);
            printf("%s\n", state->status_message);
        }
    }
    
    nk_layout_row_dynamic(ctx, widget_height, 1);
    if (nk_option_label(ctx, "Option C", state->option_selected == 2)) {
        if (state->option_selected != 2) {
            state->option_selected = 2;
            snprintf(state->status_message, sizeof(state->status_message), 
                    "Selected Option C (Scale: %.2f)", scale);
            printf("%s\n", state->status_message);
        }
    }
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "Selected: Option %c", 'A' + state->option_selected);
}

// Status component to show current application status
void render_status_component(struct nk_context* ctx, ui_state_t* state) {
    float scale = get_ui_scale_factor();
    float label_height = 25.0f * scale;
    float button_height = 30.0f * scale;
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_label(ctx, "Status & Controls:", NK_TEXT_LEFT);
    
    nk_layout_row_dynamic(ctx, label_height, 1);
    nk_labelf(ctx, NK_TEXT_LEFT, "%s", state->status_message);
    
    // Add a reset button to demonstrate easy component extension
    nk_layout_row_dynamic(ctx, button_height, 2);
    if (nk_button_label(ctx, "Reset UI State")) {
        ui_state_reset();
    }
    
    // Add a component toggle demonstration
    static int show_demo_toggle = 0;
    if (nk_button_label(ctx, show_demo_toggle ? "Hide Demo" : "Show Demo")) {
        show_demo_toggle = !show_demo_toggle;
        ui_component_set_enabled("Window Info", show_demo_toggle);
        snprintf(state->status_message, sizeof(state->status_message), 
                "Window Info component %s", show_demo_toggle ? "enabled" : "disabled");
    }
}

// =============================================================================
// UI STATE MANAGEMENT FUNCTIONS
// =============================================================================

// Update status message
void ui_state_update_status(const char* message) {
    if (message) {
        snprintf(ui_state.status_message, sizeof(ui_state.status_message), "%s", message);
    }
}

// Reset UI state to defaults
void ui_state_reset(void) {
    strcpy(ui_state.text_buffer, "Hello World!");
    ui_state.slider_value = 0.5f;
    ui_state.checkbox_value = 1;
    ui_state.option_selected = 0;
    ui_state.button_click_count = 0;
    strcpy(ui_state.status_message, "UI state reset to defaults");
    printf("UI state has been reset to defaults\n");
}

// =============================================================================
// UTILITY FUNCTIONS FOR ADDING NEW COMPONENTS
// =============================================================================

// Function to enable/disable specific UI components
void ui_component_set_enabled(const char* component_name, int enabled) {
    for (int i = 0; i < UI_COMPONENT_COUNT; i++) {
        if (strcmp(ui_components[i].name, component_name) == 0) {
            ui_components[i].enabled = enabled;
            printf("Component '%s' %s\n", component_name, enabled ? "enabled" : "disabled");
            return;
        }
    }
    printf("Component '%s' not found\n", component_name);
}

// Function to get component status
int ui_component_is_enabled(const char* component_name) {
    for (int i = 0; i < UI_COMPONENT_COUNT; i++) {
        if (strcmp(ui_components[i].name, component_name) == 0) {
            return ui_components[i].enabled;
        }
    }
    return 0; // Component not found
}

// Cleanup resources
void cleanup(void) {
    // Cleanup Nuklear resources
    if (ctx) {
        nk_glfw3_shutdown(&glfw);
        ctx = NULL;
    }
    
    // Cleanup GLFW resources
    if (window) {
        glfwDestroyWindow(window);
    }
    glfwTerminate();
}

int main(int argc, char** argv) {
    printf("Nuklear GLFW3 Demo Application - Modular UI Components\n");
    printf("Initializing modular UI component system...\n");
    printf("Available components: %zu\n", UI_COMPONENT_COUNT);
    
    // List all available components
    for (int i = 0; i < UI_COMPONENT_COUNT; i++) {
        printf("  - %s: %s\n", ui_components[i].name, 
               ui_components[i].enabled ? "enabled" : "disabled");
    }
    
    // Initialize GLFW and create window
    init_glfw();
    
    // Initialize Nuklear
    init_nuklear();
    
    // Set initial status message
    ui_state_update_status("Modular UI system initialized successfully");
    
    // Main render loop
    while (!glfwWindowShouldClose(window)) {
        // Poll events and handle input
        glfwPollEvents();
        nk_glfw3_new_frame(&glfw);
        
        // Render UI using modular component system
        render_ui(ctx);
        
        // Clear the screen
        glClearColor(0.10f, 0.18f, 0.24f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        // Render Nuklear
        nk_glfw3_render(&glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
        
        // Swap front and back buffers
        glfwSwapBuffers(window);
    }
    
    // Cleanup
    cleanup();
    
    printf("Modular UI system shut down successfully\n");
    printf("Application closed successfully\n");
    return 0;
}