// Note to assistants. dm_admin is only for functions relating to direct messaging


#define _GNU_SOURCE
#include "config.h"
#include "debug.h"
#include "api.h"
#include "../nostr_core_lib/nostr_core/nostr_core.h"
#include "../nostr_core_lib/nostr_core/nip017.h"
#include "../nostr_core_lib/nostr_core/nip044.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/stat.h>
#include <cjson/cJSON.h>
#include <libwebsockets.h>

// External database connection (from main.c)
extern sqlite3* g_db;

// Forward declarations for unified handlers
extern int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_message, size_t error_size, struct lws* wsi);
extern int handle_config_query_unified(cJSON* event, const char* query_type, char* error_message, size_t error_size, struct lws* wsi);
extern int handle_config_set_unified(cJSON* event, const char* config_key, const char* config_value, char* error_message, size_t error_size, struct lws* wsi);
extern int handle_config_update_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi);
extern int handle_system_command_unified(cJSON* event, const char* command, char* error_message, size_t error_size, struct lws* wsi);
extern int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi);
extern int handle_auth_rule_modification_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi);

// Forward declarations for tag parsing utilities
extern const char* get_first_tag_name(cJSON* event);
extern const char* get_tag_value(cJSON* event, const char* tag_name, int value_index);

// Forward declarations for config functions
extern char* get_relay_private_key(void);
extern const char* get_config_value(const char* key);
extern int get_config_bool(const char* key, int default_value);

// Forward declarations for database functions
extern int store_event(cJSON* event);
extern int broadcast_event_to_subscriptions(cJSON* event);

// Forward declarations for stats generation (moved to api.c)
extern char* generate_stats_json(void);
extern char* generate_stats_text(void);
extern char* generate_config_text(void);

// Forward declarations for NIP-17 response sender (moved to api.c)
extern int send_nip17_response(const char* sender_pubkey, const char* response_content,
                               char* error_message, size_t error_size);

// Forward declarations for config change system (moved to api.c)
extern int handle_config_confirmation(const char* admin_pubkey, const char* response);
extern int process_config_change_request(const char* admin_pubkey, const char* message);

// Forward declarations for config change system (moved to api.c)
#include "api.h"


// Forward declarations for admin event processing
extern int process_admin_event_in_config(cJSON* event, char* error_message, size_t error_size, struct lws* wsi);

// Forward declarations for NIP-17 processing
int is_nip17_gift_wrap_for_relay(cJSON* event);
int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t error_size, struct lws* wsi);
cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message, size_t error_size, struct lws* wsi);

// Forward declarations for API functions (moved from dm_admin.c)
extern int send_admin_response(const char* sender_pubkey, const char* response_content, const char* request_id,
                              char* error_message, size_t error_size, struct lws* wsi);
extern int validate_sql_query(const char* query, char* error_message, size_t error_size);
extern char* execute_sql_query(const char* query, const char* request_id, char* error_message, size_t error_size);
extern int handle_sql_query_unified(cJSON* event, const char* query, char* error_message, size_t error_size, struct lws* wsi);

// ================================
// DIRECT MESSAGING ADMIN SYSTEM
// ================================

// Process direct command arrays (DM control system)
// This handles commands sent as direct JSON arrays, not wrapped in inner events
// Note: create_relay_event is NOT supported via DMs - use Kind 23456 events only
int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_message, size_t error_size, struct lws* wsi) {
    if (!command_array || !cJSON_IsArray(command_array) || !event) {
        DEBUG_ERROR("DM Admin: Invalid command array or event");
        snprintf(error_message, error_size, "invalid: null command array or event");
        return -1;
    }

    int array_size = cJSON_GetArraySize(command_array);
    if (array_size < 1) {
        DEBUG_ERROR("DM Admin: Empty command array");
        snprintf(error_message, error_size, "invalid: empty command array");
        return -1;
    }

    // Get the command type from the first element
    cJSON* command_item = cJSON_GetArrayItem(command_array, 0);
    if (!command_item || !cJSON_IsString(command_item)) {
        DEBUG_ERROR("DM Admin: First element is not a string command");
        snprintf(error_message, error_size, "invalid: command must be a string");
        return -1;
    }

    const char* command_type = cJSON_GetStringValue(command_item);

    // Create synthetic tags from the command array for unified handler compatibility
    cJSON* synthetic_tags = cJSON_CreateArray();

    // Add the command as the first tag
    cJSON* command_tag = cJSON_CreateArray();
    cJSON_AddItemToArray(command_tag, cJSON_CreateString(command_type));

    // Add remaining array elements as tag parameters
    for (int i = 1; i < array_size; i++) {
        cJSON* param = cJSON_GetArrayItem(command_array, i);
        if (param) {
            if (cJSON_IsString(param)) {
                cJSON_AddItemToArray(command_tag, cJSON_CreateString(cJSON_GetStringValue(param)));
            } else {
                // Convert non-string parameters to strings for tag compatibility
                char* param_str = cJSON_Print(param);
                if (param_str) {
                    // Remove quotes from JSON string representation
                    if (param_str[0] == '"' && param_str[strlen(param_str)-1] == '"') {
                        param_str[strlen(param_str)-1] = '\0';
                        cJSON_AddItemToArray(command_tag, cJSON_CreateString(param_str + 1));
                    } else {
                        cJSON_AddItemToArray(command_tag, cJSON_CreateString(param_str));
                    }
                    free(param_str);
                }
            }
        }
    }

    cJSON_AddItemToArray(synthetic_tags, command_tag);

    // Add existing event tags
    cJSON* existing_tags = cJSON_GetObjectItem(event, "tags");
    if (existing_tags && cJSON_IsArray(existing_tags)) {
        cJSON* tag = NULL;
        cJSON_ArrayForEach(tag, existing_tags) {
            cJSON_AddItemToArray(synthetic_tags, cJSON_Duplicate(tag, 1));
        }
    }

    // Temporarily replace event tags with synthetic tags
    cJSON_ReplaceItemInObject(event, "tags", synthetic_tags);

    // Route to appropriate handler based on command type
    int result = -1;

    if (strcmp(command_type, "auth_query") == 0) {
        const char* query_type = get_tag_value(event, "auth_query", 1);
        if (!query_type) {
            DEBUG_ERROR("DM Admin: Missing auth_query type parameter");
            snprintf(error_message, error_size, "invalid: missing auth_query type");
        } else {
            result = handle_auth_query_unified(event, query_type, error_message, error_size, wsi);
        }
    }
    else if (strcmp(command_type, "config_query") == 0) {
        const char* query_type = get_tag_value(event, "config_query", 1);
        if (!query_type) {
            DEBUG_ERROR("DM Admin: Missing config_query type parameter");
            snprintf(error_message, error_size, "invalid: missing config_query type");
        } else {
            result = handle_config_query_unified(event, query_type, error_message, error_size, wsi);
        }
    }
    else if (strcmp(command_type, "config_set") == 0) {
        const char* config_key = get_tag_value(event, "config_set", 1);
        const char* config_value = get_tag_value(event, "config_set", 2);
        if (!config_key || !config_value) {
            DEBUG_ERROR("DM Admin: Missing config_set parameters");
            snprintf(error_message, error_size, "invalid: missing config_set key or value");
        } else {
            result = handle_config_set_unified(event, config_key, config_value, error_message, error_size, wsi);
        }
    }
    else if (strcmp(command_type, "config_update") == 0) {
        result = handle_config_update_unified(event, error_message, error_size, wsi);
    }
    else if (strcmp(command_type, "system_command") == 0) {
        const char* command = get_tag_value(event, "system_command", 1);
        if (!command) {
            DEBUG_ERROR("DM Admin: Missing system_command type parameter");
            snprintf(error_message, error_size, "invalid: missing system_command type");
        } else {
            result = handle_system_command_unified(event, command, error_message, error_size, wsi);
        }
    }
    else if (strcmp(command_type, "stats_query") == 0) {
        result = handle_stats_query_unified(event, error_message, error_size, wsi);
    }
    else if (strcmp(command_type, "whitelist") == 0 || strcmp(command_type, "blacklist") == 0) {
        result = handle_auth_rule_modification_unified(event, error_message, error_size, wsi);
    }
    else if (strcmp(command_type, "sql_query") == 0) {
        const char* query = get_tag_value(event, "sql_query", 1);
        if (!query) {
            DEBUG_ERROR("DM Admin: Missing sql_query parameter");
            snprintf(error_message, error_size, "invalid: missing SQL query");
        } else {
            result = handle_sql_query_unified(event, query, error_message, error_size, wsi);
        }
    }
    else {
        DEBUG_ERROR("DM Admin: Unknown command type");
        printf("  Unknown command: %s\n", command_type);
        snprintf(error_message, error_size, "invalid: unknown DM command type '%s'", command_type);
    }

    if (result != 0) {
        DEBUG_ERROR("DM Admin: Command processing failed");
    }

    return result;
}







// Main NIP-17 processing function
cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message, size_t error_size, struct lws* wsi) {
    if (!gift_wrap_event || !error_message) {
        return NULL;
    }

    DEBUG_INFO("DM_ADMIN: Received potential NIP-17 gift wrap event for processing");

    // Step 1: Validate it's addressed to us
    if (!is_nip17_gift_wrap_for_relay(gift_wrap_event)) {
        DEBUG_INFO("DM_ADMIN: Event is not a valid gift wrap for this relay - rejecting");
        strncpy(error_message, "NIP-17: Event is not a valid gift wrap for this relay", error_size - 1);
        return NULL;
    }

    DEBUG_INFO("DM_ADMIN: Valid NIP-17 gift wrap confirmed for this relay");

    // Step 2: Get relay private key for decryption
    char* relay_privkey_hex = get_relay_private_key();
    if (!relay_privkey_hex) {
        DEBUG_INFO("DM_ADMIN: Could not get relay private key for decryption");
        strncpy(error_message, "NIP-17: Could not get relay private key for decryption", error_size - 1);
        return NULL;
    }

    DEBUG_INFO("DM_ADMIN: Retrieved relay private key for decryption");

    // Convert hex private key to bytes
    unsigned char relay_privkey[32];
    if (nostr_hex_to_bytes(relay_privkey_hex, relay_privkey, sizeof(relay_privkey)) != 0) {
        DEBUG_ERROR("NIP-17: Failed to convert relay private key from hex");
        free(relay_privkey_hex);
        strncpy(error_message, "NIP-17: Failed to convert relay private key", error_size - 1);
        return NULL;
    }
    free(relay_privkey_hex);

    DEBUG_INFO("DM_ADMIN: Converted relay private key to bytes successfully");

    // Step 3: Decrypt and parse inner event using library function
    DEBUG_INFO("DM_ADMIN: Attempting to decrypt NIP-17 gift wrap using nostr_nip17_receive_dm");
    cJSON* inner_dm = nostr_nip17_receive_dm(gift_wrap_event, relay_privkey);
    if (!inner_dm) {
        DEBUG_INFO("DM_ADMIN: nostr_nip17_receive_dm returned NULL - decryption failed");
        // Debug: Print the gift wrap event
        char* gift_wrap_debug = cJSON_Print(gift_wrap_event);
        if (gift_wrap_debug) {
            char debug_msg[1024];
            snprintf(debug_msg, sizeof(debug_msg), "NIP-17: Gift wrap event: %.500s", gift_wrap_debug);
            DEBUG_ERROR(debug_msg);
            free(gift_wrap_debug);
        }
        // Debug: Check if private key is valid
        char privkey_hex[65];
        for (int i = 0; i < 32; i++) {
            sprintf(privkey_hex + (i * 2), "%02x", relay_privkey[i]);
        }
        privkey_hex[64] = '\0';

        DEBUG_INFO("DM_ADMIN: NIP-17 decryption failed - returning error");
        strncpy(error_message, "NIP-17: Failed to decrypt and parse inner DM event", error_size - 1);
        return NULL;
    }

    DEBUG_INFO("DM_ADMIN: Successfully decrypted NIP-17 gift wrap, processing inner DM");

    // Step 4: Process admin command
    DEBUG_INFO("DM_ADMIN: Processing decrypted admin command");
    int result = process_nip17_admin_command(inner_dm, error_message, error_size, wsi);
    DEBUG_INFO("DM_ADMIN: Admin command processing completed with result: %d", result);

    // Step 5: For plain text commands (stats/config), the response is already handled
    // Only create a generic response for other command types that don't handle their own responses
    if (result == 0) {
        // Extract content to check if it's a plain text command
        cJSON* content_obj = cJSON_GetObjectItem(inner_dm, "content");
        if (content_obj && cJSON_IsString(content_obj)) {
            const char* dm_content = cJSON_GetStringValue(content_obj);
            
            // Check if it's a plain text command that already handled its response
            char content_lower[256];
            size_t content_len = strlen(dm_content);
            size_t copy_len = content_len < sizeof(content_lower) - 1 ? content_len : sizeof(content_lower) - 1;
            memcpy(content_lower, dm_content, copy_len);
            content_lower[copy_len] = '\0';
            
            // Convert to lowercase
            for (size_t i = 0; i < copy_len; i++) {
                if (content_lower[i] >= 'A' && content_lower[i] <= 'Z') {
                    content_lower[i] = content_lower[i] + 32;
                }
            }
            
            // If it's a plain text stats or config command, don't create additional response
            if (strstr(content_lower, "stats") != NULL || strstr(content_lower, "statistics") != NULL ||
                strstr(content_lower, "config") != NULL || strstr(content_lower, "configuration") != NULL) {
                cJSON_Delete(inner_dm);
                return NULL; // No additional response needed
            }
            
            // Check if it's a JSON array command that might be stats
            cJSON* command_array = cJSON_Parse(dm_content);
            if (command_array && cJSON_IsArray(command_array) && cJSON_GetArraySize(command_array) > 0) {
                cJSON* first_item = cJSON_GetArrayItem(command_array, 0);
                if (cJSON_IsString(first_item) && strcmp(cJSON_GetStringValue(first_item), "stats") == 0) {
                    cJSON_Delete(command_array);
                    cJSON_Delete(inner_dm);
                    return NULL; // No additional response needed
                }
                cJSON_Delete(command_array);
            }
        }
    } else if (result > 0) {
        // Command was handled and response was sent, don't create generic response
        cJSON_Delete(inner_dm);
        return NULL;

        // Get sender pubkey for response from the decrypted DM event
        cJSON* sender_pubkey_obj = cJSON_GetObjectItem(inner_dm, "pubkey");
        if (sender_pubkey_obj && cJSON_IsString(sender_pubkey_obj)) {
            const char* sender_pubkey = cJSON_GetStringValue(sender_pubkey_obj);

            // Create success response using library function
            char response_content[1024];
            snprintf(response_content, sizeof(response_content),
                    "[\"command_processed\", \"success\", \"%s\"]", "NIP-17 admin command executed");

            // Get relay pubkey for creating DM event
            const char* relay_pubkey = get_config_value("relay_pubkey");
            if (relay_pubkey) {
                cJSON* success_dm = nostr_nip17_create_chat_event(
                    response_content,                // message content
                    (const char**)&sender_pubkey,     // recipient pubkeys
                    1,                                // num recipients
                    NULL,                             // subject (optional)
                    NULL,                             // reply_to_event_id (optional)
                    NULL,                             // reply_relay_url (optional)
                    relay_pubkey                      // sender pubkey
                );

                if (success_dm) {
                    cJSON* success_gift_wraps[1];
                    // Get timestamp delay configuration
                    long max_delay_sec = get_config_int("nip59_timestamp_max_delay_sec", 0);

                    int send_result = nostr_nip17_send_dm(
                        success_dm,                       // dm_event
                        (const char**)&sender_pubkey,     // recipient_pubkeys
                        1,                                // num_recipients
                        relay_privkey,                    // sender_private_key
                        success_gift_wraps,               // gift_wraps_out
                        1,                                // max_gift_wraps
                        max_delay_sec                     // max_delay_sec
                    );

                    cJSON_Delete(success_dm);

                    if (send_result == 1 && success_gift_wraps[0]) {
                        // Store the response gift wrap in database
                        store_event(success_gift_wraps[0]);

                        // Return the response event for broadcasting
                        cJSON_Delete(inner_dm);
                        return success_gift_wraps[0];
                    }
                }
            }
        }
    }

    cJSON_Delete(inner_dm);
    return NULL;
}

// Check if decrypted content is a direct command array (DM system)
// Returns 1 if it's a valid command array, 0 if it should fall back to inner event parsing
int is_dm_command_array(const char* decrypted_content) {
    if (!decrypted_content) {
        return 0;
    }

    // Quick check: must start with '[' for JSON array
    if (decrypted_content[0] != '[') {
        return 0;
    }

    // Try to parse as JSON array
    cJSON* parsed = cJSON_Parse(decrypted_content);
    if (!parsed) {
        return 0;
    }

    int is_array = cJSON_IsArray(parsed);
    cJSON_Delete(parsed);

    return is_array;
}


// =============================================================================
// NIP-17 GIFT WRAP PROCESSING FUNCTIONS
// =============================================================================

// Check if an event is a NIP-17 gift wrap addressed to this relay
int is_nip17_gift_wrap_for_relay(cJSON* event) {
    if (!event || !cJSON_IsObject(event)) {
        return 0;
    }

    // Check kind
    cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
    if (!kind_obj || !cJSON_IsNumber(kind_obj) || (int)cJSON_GetNumberValue(kind_obj) != 1059) {
        return 0;
    }

    // Check tags for "p" tag with relay pubkey
    cJSON* tags = cJSON_GetObjectItem(event, "tags");
    if (!tags || !cJSON_IsArray(tags)) {
        return 0;
    }

    const char* relay_pubkey = get_config_value("relay_pubkey");
    if (!relay_pubkey) {
        DEBUG_ERROR("NIP-17: Could not get relay pubkey for validation");
        return 0;
    }

    // Look for "p" tag with relay pubkey
    cJSON* tag = NULL;
    cJSON_ArrayForEach(tag, tags) {
        if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
            cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
            cJSON* tag_value = cJSON_GetArrayItem(tag, 1);

            if (tag_name && cJSON_IsString(tag_name) &&
                strcmp(cJSON_GetStringValue(tag_name), "p") == 0 &&
                tag_value && cJSON_IsString(tag_value) &&
                strcmp(cJSON_GetStringValue(tag_value), relay_pubkey) == 0) {
                return 1; // Found matching p tag
            }
        }
    }

    return 0; // No matching p tag found
}

// Process NIP-17 admin command from decrypted DM content
int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t error_size, struct lws* wsi) {
    if (!dm_event || !error_message) {
        return -1;
    }

    DEBUG_INFO("DM_ADMIN: Processing NIP-17 admin command from decrypted DM");

    // Extract content from DM
    cJSON* content_obj = cJSON_GetObjectItem(dm_event, "content");
    if (!content_obj || !cJSON_IsString(content_obj)) {
        DEBUG_INFO("DM_ADMIN: DM missing content field");
        strncpy(error_message, "NIP-17: DM missing content", error_size - 1);
        return -1;
    }

    const char* dm_content = cJSON_GetStringValue(content_obj);
    DEBUG_INFO("DM_ADMIN: Extracted DM content: %.100s%s", dm_content, strlen(dm_content) > 100 ? "..." : "");

    // Check if sender is admin before processing any commands
    cJSON* sender_pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
    if (!sender_pubkey_obj || !cJSON_IsString(sender_pubkey_obj)) {
        DEBUG_INFO("DM_ADMIN: DM missing sender pubkey - treating as user DM");
        return 0; // Not an error, just treat as user DM
    }
    const char* sender_pubkey = cJSON_GetStringValue(sender_pubkey_obj);

    // Check if sender is admin
    const char* admin_pubkey = get_config_value("admin_pubkey");
    int is_admin = admin_pubkey && strlen(admin_pubkey) > 0 && strcmp(sender_pubkey, admin_pubkey) == 0;

    DEBUG_INFO("DM_ADMIN: Sender pubkey: %.16s... (admin: %s)", sender_pubkey, is_admin ? "YES" : "NO");

    // Parse DM content as JSON array of commands
    DEBUG_INFO("DM_ADMIN: Attempting to parse DM content as JSON command array");
    cJSON* command_array = cJSON_Parse(dm_content);
    if (!command_array || !cJSON_IsArray(command_array)) {
        DEBUG_INFO("DM_ADMIN: Content is not a JSON array, checking for plain text commands");
        // If content is not a JSON array, check for plain text commands
        if (is_admin) {
            DEBUG_INFO("DM_ADMIN: Processing plain text admin command");
            // Convert content to lowercase for case-insensitive matching
            char content_lower[256];
            size_t content_len = strlen(dm_content);
            size_t copy_len = content_len < sizeof(content_lower) - 1 ? content_len : sizeof(content_lower) - 1;
            memcpy(content_lower, dm_content, copy_len);
            content_lower[copy_len] = '\0';

            // Convert to lowercase
            for (size_t i = 0; i < copy_len; i++) {
                if (content_lower[i] >= 'A' && content_lower[i] <= 'Z') {
                    content_lower[i] = content_lower[i] + 32;
                }
            }

            // Check for stats commands
            if (strstr(content_lower, "stats") != NULL || strstr(content_lower, "statistics") != NULL) {
                DEBUG_INFO("DM_ADMIN: Processing stats command");
                char* stats_text = generate_stats_text();
                if (!stats_text) {
                    DEBUG_INFO("DM_ADMIN: Failed to generate stats text");
                    return -1;
                }

                char error_msg[256];
                int result = send_nip17_response(sender_pubkey, stats_text, error_msg, sizeof(error_msg));
                free(stats_text);

                if (result != 0) {
                    DEBUG_ERROR(error_msg);
                    return -1;
                }

                DEBUG_INFO("DM_ADMIN: Stats command processed successfully");
                return 0;
            }
            // Check for config commands
            else if (strstr(content_lower, "config") != NULL || strstr(content_lower, "configuration") != NULL) {
                DEBUG_INFO("DM_ADMIN: Processing config command");
                char* config_text = generate_config_text();
                if (!config_text) {
                    DEBUG_INFO("DM_ADMIN: Failed to generate config text");
                    return -1;
                }

                char error_msg[256];
                int result = send_nip17_response(sender_pubkey, config_text, error_msg, sizeof(error_msg));
                free(config_text);

                if (result != 0) {
                    DEBUG_ERROR(error_msg);
                    return -1;
                }

                DEBUG_INFO("DM_ADMIN: Config command processed successfully");
                return 0;
            }
            // Check for status commands
            else if (strstr(content_lower, "status") != NULL) {
                DEBUG_INFO("DM_ADMIN: Processing status command");

                // Create synthetic event for system_command handler
                cJSON* synthetic_event = cJSON_CreateObject();
                cJSON_AddNumberToObject(synthetic_event, "kind", 23456);
                cJSON_AddStringToObject(synthetic_event, "pubkey", sender_pubkey);

                // Create tags array with system_command
                cJSON* tags = cJSON_CreateArray();
                cJSON* cmd_tag = cJSON_CreateArray();
                cJSON_AddItemToArray(cmd_tag, cJSON_CreateString("system_command"));
                cJSON_AddItemToArray(cmd_tag, cJSON_CreateString("system_status"));
                cJSON_AddItemToArray(tags, cmd_tag);
                cJSON_AddItemToObject(synthetic_event, "tags", tags);

                char error_msg[256];
                int result = handle_system_command_unified(synthetic_event, "system_status", error_msg, sizeof(error_msg), wsi);
                cJSON_Delete(synthetic_event);

                if (result != 0) {
                    DEBUG_ERROR(error_msg);
                    return -1;
                }

                DEBUG_INFO("DM_ADMIN: Status command processed successfully");
                return 0;
            }
            else {
                DEBUG_INFO("DM_ADMIN: Checking for confirmation or config change requests");
                // Check if it's a confirmation response (yes/no)
                int confirmation_result = handle_config_confirmation(sender_pubkey, dm_content);
                if (confirmation_result != 0) {
                    if (confirmation_result > 0) {
                        DEBUG_INFO("DM_ADMIN: Configuration confirmation processed successfully");
                    } else if (confirmation_result == -2) {
                        DEBUG_INFO("DM_ADMIN: No pending changes to confirm");
                        // No pending changes
                        char no_pending_msg[256];
                        snprintf(no_pending_msg, sizeof(no_pending_msg),
                            "❌ No Pending Changes\n"
                            "━━━━━━━━━━━━━━━━━━━━━━\n"
                            "\n"
                            "You don't have any pending configuration changes to confirm.\n"
                            "\n"
                            "Send a configuration command first (e.g., 'auth_enabled true')."
                        );
                        send_nip17_response(sender_pubkey, no_pending_msg, NULL, 0);
                    }
                    return 0;
                }

                // Check if it's a configuration change request
                int config_result = process_config_change_request(sender_pubkey, dm_content);
                if (config_result != 0) {
                    if (config_result > 0) {
                        DEBUG_INFO("DM_ADMIN: Configuration change request processed successfully");
                        return 1; // Return positive value to indicate response was handled
                    } else {
                        DEBUG_ERROR("NIP-17: Configuration change request failed");
                        return -1; // Return error to prevent generic success response
                    }
                }

                DEBUG_INFO("DM_ADMIN: Unrecognized plain text admin command");
                return 0; // Admin sent unrecognized plain text, treat as user DM
            }
        } else {
            DEBUG_INFO("DM_ADMIN: Non-admin user sent plain text - treating as user DM");
            // Not admin, treat as user DM
            return 0;
        }
    }

    DEBUG_INFO("DM_ADMIN: Successfully parsed JSON command array");

    // Check if this is a "stats" command
    if (cJSON_GetArraySize(command_array) > 0) {
        cJSON* first_item = cJSON_GetArrayItem(command_array, 0);
        if (cJSON_IsString(first_item) && strcmp(cJSON_GetStringValue(first_item), "stats") == 0) {
            DEBUG_INFO("DM_ADMIN: Processing JSON stats command");
            // Get sender pubkey for response
            cJSON* sender_pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
            if (!sender_pubkey_obj || !cJSON_IsString(sender_pubkey_obj)) {
                cJSON_Delete(command_array);
                DEBUG_INFO("DM_ADMIN: DM missing sender pubkey for stats command");
                strncpy(error_message, "NIP-17: DM missing sender pubkey", error_size - 1);
                return -1;
            }
            const char* sender_pubkey = cJSON_GetStringValue(sender_pubkey_obj);

            // Generate stats JSON (for JSON array commands, use JSON format)
            char* stats_json = generate_stats_json();
            if (!stats_json) {
                cJSON_Delete(command_array);
                DEBUG_INFO("DM_ADMIN: Failed to generate stats JSON");
                strncpy(error_message, "NIP-17: Failed to generate stats", error_size - 1);
                return -1;
            }

            char error_msg[256];
            int result = send_nip17_response(sender_pubkey, stats_json, error_msg, sizeof(error_msg));
            free(stats_json);
            cJSON_Delete(command_array);

            if (result != 0) {
                DEBUG_ERROR(error_msg);
                strncpy(error_message, error_msg, error_size - 1);
                return -1;
            }

            DEBUG_INFO("DM_ADMIN: JSON stats command processed successfully");
            return 0;
        }
    }

    DEBUG_INFO("DM_ADMIN: Delegating to unified admin processing for command array");
    // For other commands, delegate to existing admin processing
    // Create a synthetic kind 23456 event with the DM content
    cJSON* synthetic_event = cJSON_CreateObject();
    cJSON_AddNumberToObject(synthetic_event, "kind", 23456);
    cJSON_AddStringToObject(synthetic_event, "content", dm_content);

    // Copy pubkey from DM
    cJSON* pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
    if (pubkey_obj && cJSON_IsString(pubkey_obj)) {
        cJSON_AddStringToObject(synthetic_event, "pubkey", cJSON_GetStringValue(pubkey_obj));
    }

    // Copy tags from DM
    cJSON* tags = cJSON_GetObjectItem(dm_event, "tags");
    if (tags) {
        cJSON_AddItemToObject(synthetic_event, "tags", cJSON_Duplicate(tags, 1));
    }

    // Process as regular admin event
    DEBUG_INFO("DM_ADMIN: Processing synthetic admin event");
    int result = process_admin_event_in_config(synthetic_event, error_message, error_size, wsi);

    cJSON_Delete(synthetic_event);
    cJSON_Delete(command_array);

    DEBUG_INFO("DM_ADMIN: Unified admin processing completed with result: %d", result);
    return result;
}