/*
 * Ginxsom Blossom Server - FastCGI Application
 * Handles HEAD requests and other dynamic operations
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <fcgi_stdio.h>
#include <sqlite3.h>
#include <sys/stat.h>
#include <time.h>
#include <stdint.h>
#include "ginxsom.h"

// Detailed debugging macros (matching test_auth_debug.c)
#define LOG_STEP(step, msg, ...) fprintf(stderr, "STEP %s: " msg "\n", step, ##__VA_ARGS__)
#define LOG_SUCCESS(msg, ...) fprintf(stderr, "SUCCESS: " msg "\n", ##__VA_ARGS__)
#define LOG_ERROR(msg, ...) fprintf(stderr, "ERROR: " msg "\n", ##__VA_ARGS__)
#define LOG_INFO(msg, ...) fprintf(stderr, "ℹINFO: " msg "\n", ##__VA_ARGS__)
#define LOG_DIVIDER() fprintf(stderr, "═══════════════════════════════════════════════════════════════════\n")

#define MAX_SHA256_LEN 65
#define MAX_PATH_LEN 512
#define MAX_MIME_LEN 128

// Database path
#define DB_PATH "db/ginxsom.db"

// Function declarations
void send_error_response(int status_code, const char* error_type, const char* message, const char* details);
void log_request(const char* method, const char* uri, const char* auth_status, int status_code);

// Blob metadata structure
typedef struct {
    char sha256[MAX_SHA256_LEN];
    long size;
    char type[MAX_MIME_LEN];
    long uploaded_at;
    char filename[256];
    int found;
} blob_metadata_t;

// Insert blob metadata into database
int insert_blob_metadata(const char* sha256, long size, const char* type, 
                         long uploaded_at, const char* uploader_pubkey, 
                         const char* filename) {
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READWRITE, NULL);
    if (rc) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return 0;
    }
    
    const char* sql = "INSERT INTO blobs (sha256, size, type, uploaded_at, uploader_pubkey, filename) VALUES (?, ?, ?, ?, ?, ?)";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 0;
    }
    
    // Bind parameters
    sqlite3_bind_text(stmt, 1, sha256, -1, SQLITE_STATIC);
    sqlite3_bind_int64(stmt, 2, size);
    sqlite3_bind_text(stmt, 3, type, -1, SQLITE_STATIC);
    sqlite3_bind_int64(stmt, 4, uploaded_at);
    if (uploader_pubkey) {
        sqlite3_bind_text(stmt, 5, uploader_pubkey, -1, SQLITE_STATIC);
    } else {
        sqlite3_bind_null(stmt, 5);
    }
    if (filename) {
        sqlite3_bind_text(stmt, 6, filename, -1, SQLITE_STATIC);
    } else {
        sqlite3_bind_null(stmt, 6);
    }
    
    rc = sqlite3_step(stmt);
    
    int success = 0;
    if (rc == SQLITE_DONE) {
        success = 1;
    } else if (rc == SQLITE_CONSTRAINT) {
        // This is actually OK - blob already exists with same hash
        success = 1;
    } else {
        success = 0;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return success;
}

// Get blob metadata from database
int get_blob_metadata(const char* sha256, blob_metadata_t* metadata) {
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    fprintf(stderr, "DEBUG: get_blob_metadata() called with sha256='%s'\r\n", sha256);
    fprintf(stderr, "DEBUG: Opening database at path: %s\r\n", DB_PATH);
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        fprintf(stderr, "DEBUG: Database open FAILED: %s\r\n", sqlite3_errmsg(db));
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return 0;
    }
    
    fprintf(stderr, "DEBUG: Database opened successfully\r\n");
    
    const char* sql = "SELECT sha256, size, type, uploaded_at, filename FROM blobs WHERE sha256 = ?";
    fprintf(stderr, "DEBUG: Preparing SQL: %s\r\n", sql);
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "DEBUG: SQL prepare FAILED: %s\r\n", sqlite3_errmsg(db));
        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 0;
    }
    
    fprintf(stderr, "DEBUG: SQL prepared successfully\r\n");
    fprintf(stderr, "DEBUG: Binding parameter sha256='%s'\r\n", sha256);
    
    sqlite3_bind_text(stmt, 1, sha256, -1, SQLITE_STATIC);
    
    fprintf(stderr, "DEBUG: Executing SQL query...\r\n");
    rc = sqlite3_step(stmt);
    fprintf(stderr, "DEBUG: sqlite3_step() returned: %d (SQLITE_ROW=%d, SQLITE_DONE=%d)\r\n", 
           rc, SQLITE_ROW, SQLITE_DONE);
    
    if (rc == SQLITE_ROW) {
        fprintf(stderr, "DEBUG: Row found! Extracting metadata...\r\n");
        strncpy(metadata->sha256, (char*)sqlite3_column_text(stmt, 0), MAX_SHA256_LEN-1);
        metadata->size = sqlite3_column_int64(stmt, 1);
        strncpy(metadata->type, (char*)sqlite3_column_text(stmt, 2), MAX_MIME_LEN-1);
        metadata->uploaded_at = sqlite3_column_int64(stmt, 3);
        const char* filename = (char*)sqlite3_column_text(stmt, 4);
        if (filename) {
            strncpy(metadata->filename, filename, 255);
        } else {
            metadata->filename[0] = '\0';
        }
        metadata->found = 1;
        fprintf(stderr, "DEBUG: Metadata extracted - size=%ld, type='%s'\r\n", 
               metadata->size, metadata->type);
    } else {
        fprintf(stderr, "DEBUG: No row found for sha256='%s'\r\n", sha256);
        metadata->found = 0;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    fprintf(stderr, "DEBUG: Database closed, returning %d\r\n", metadata->found);
    return metadata->found;
}

// Check if physical file exists (with extension based on MIME type)
int file_exists_with_type(const char* sha256, const char* mime_type) {
    char filepath[MAX_PATH_LEN];
    const char* extension = "";
    
    // Determine file extension based on MIME type
    if (strstr(mime_type, "image/jpeg")) {
        extension = ".jpg";
    } else if (strstr(mime_type, "image/webp")) {
        extension = ".webp";
    } else if (strstr(mime_type, "image/png")) {
        extension = ".png";
    } else if (strstr(mime_type, "image/gif")) {
        extension = ".gif";
    } else if (strstr(mime_type, "video/mp4")) {
        extension = ".mp4";
    } else if (strstr(mime_type, "video/webm")) {
        extension = ".webm";
    } else if (strstr(mime_type, "audio/mpeg")) {
        extension = ".mp3";
    } else if (strstr(mime_type, "audio/ogg")) {
        extension = ".ogg";
    } else if (strstr(mime_type, "text/plain")) {
        extension = ".txt";
    }
    
    snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256, extension);
    
    fprintf(stderr, "DEBUG: file_exists_with_type() checking path: '%s' (MIME: %s)\r\n", filepath, mime_type);
    
    struct stat st;
    int result = stat(filepath, &st);
    fprintf(stderr, "DEBUG: stat() returned: %d (0=success, -1=fail)\r\n", result);
    
    if (result == 0) {
        fprintf(stderr, "DEBUG: File exists! Size: %ld bytes\r\n", st.st_size);
        return 1;
    } else {
        fprintf(stderr, "DEBUG: File does not exist or stat failed\r\n");
        return 0;
    }
}

// Handle HEAD request for blob
void handle_head_request(const char* sha256) {
    blob_metadata_t metadata = {0};
    
    fprintf(stderr, "DEBUG: handle_head_request called with sha256=%s\r\n", sha256);
    
    // Validate SHA-256 format (64 hex characters)
    if (strlen(sha256) != 64) {
        fprintf(stderr, "DEBUG: SHA-256 length validation failed: %zu\r\n", strlen(sha256));
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Invalid SHA-256 hash format\n");
        return;
    }
    
    fprintf(stderr, "DEBUG: SHA-256 length validation passed\r\n");
    
    // Check if blob exists in database - this is the single source of truth
    if (!get_blob_metadata(sha256, &metadata)) {
        fprintf(stderr, "DEBUG: Database lookup failed for sha256=%s\r\n", sha256);
        printf("Status: 404 Not Found\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Blob not found\n");
        return;
    }
    
    fprintf(stderr, "DEBUG: Database lookup succeeded - blob exists\r\n");
    
    // Return successful HEAD response with metadata from database
    printf("Status: 200 OK\r\n");
    printf("Content-Type: %s\r\n", metadata.type);
    printf("Content-Length: %ld\r\n", metadata.size);
    printf("Cache-Control: public, max-age=31536000, immutable\r\n");
    printf("ETag: \"%s\"\r\n", metadata.sha256);
    
    // Add timing header for debugging
    printf("X-Ginxsom-Server: FastCGI\r\n");
    printf("X-Ginxsom-Timestamp: %ld\r\n", time(NULL));
    
    if (strlen(metadata.filename) > 0) {
        printf("X-Original-Filename: %s\r\n", metadata.filename);
    }
    
    printf("\r\n");
    // HEAD request - no body content
}

// Extract SHA-256 from request URI (Blossom compliant - ignores any extension)
const char* extract_sha256_from_uri(const char* uri) {
    static char sha256_buffer[MAX_SHA256_LEN];
    
    if (!uri || uri[0] != '/') {
        return NULL;
    }
    
    const char* start = uri + 1; // Skip leading '/'
    
    // Extract exactly 64 hex characters, ignoring anything after (extensions, etc.)
    int len = 0;
    for (int i = 0; i < 64 && start[i] != '\0'; i++) {
        char c = start[i];
        if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
            // If we hit a non-hex character before 64 chars, it's invalid
            if (len < 64) {
                return NULL;
            }
            break;
        }
        sha256_buffer[i] = c;
        len = i + 1;
    }
    
    // Must be exactly 64 hex characters
    if (len != 64) {
        return NULL;
    }
    
    sha256_buffer[64] = '\0';
    return sha256_buffer;
}

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//             BUD 02 - Upload & Authentication
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

// Parse Authorization header and extract JSON event
int parse_authorization_header(const char* auth_header, char* event_json, size_t json_size) {
    if (!auth_header || !event_json) {
        fprintf(stderr, "DEBUG: parse_authorization_header - invalid parameters: auth_header=%p, event_json=%p\n",
               (void*)auth_header, (void*)event_json);
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    fprintf(stderr, "DEBUG: parse_authorization_header called with header: %.50s...\n", auth_header);
    
    // Check for "Nostr " prefix (case-insensitive)
    const char* prefix = "nostr ";
    size_t prefix_len = strlen(prefix);
    
    if (strncasecmp(auth_header, prefix, prefix_len) != 0) {
        fprintf(stderr, "DEBUG: Authorization header missing 'Nostr ' prefix (found: %.10s)\n", auth_header);
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    // Extract base64 encoded event after "Nostr "
    const char* base64_event = auth_header + prefix_len;
    fprintf(stderr, "DEBUG: Extracted base64 event (length=%zu): %.100s...\n", strlen(base64_event), base64_event);
    
    // Decode base64 to JSON using nostr_core_lib base64 decode
    unsigned char decoded_buffer[4096];
    size_t decoded_len = base64_decode(base64_event, decoded_buffer);
    
    fprintf(stderr, "DEBUG: Base64 decode result - decoded_len=%zu\n", decoded_len);
    
    if (decoded_len == 0) {
        fprintf(stderr, "DEBUG: Failed to decode base64 event - base64_decode returned 0\n");
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    if (decoded_len >= json_size) {
        fprintf(stderr, "DEBUG: Decoded JSON too large for buffer (decoded_len=%zu, json_size=%zu)\n", decoded_len, json_size);
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    // Copy decoded JSON to output buffer
    memcpy(event_json, decoded_buffer, decoded_len);
    event_json[decoded_len] = '\0';
    
    fprintf(stderr, "DEBUG: Successfully decoded JSON (length=%zu): %s\n", decoded_len, event_json);
    return NOSTR_SUCCESS;
}

// Validate Blossom-specific event requirements (kind 24242)
int validate_blossom_event(cJSON* event, const char* expected_hash, const char* method) {
    if (!event) {
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    fprintf(stderr, "DEBUG: Validating Blossom event\r\n");
    
    // Check event kind (must be 24242 for Blossom uploads)
    cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
    if (!kind_json || !cJSON_IsNumber(kind_json)) {
        fprintf(stderr, "DEBUG: Event missing or invalid 'kind' field\r\n");
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    int kind = cJSON_GetNumberValue(kind_json);
    if (kind != 24242) {
        fprintf(stderr, "DEBUG: Event kind %d is not 24242 (Blossom upload)\r\n", kind);
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    // Check that created_at exists (basic validation)
    cJSON* created_at_json = cJSON_GetObjectItem(event, "created_at");
    if (!created_at_json || !cJSON_IsNumber(created_at_json)) {
        fprintf(stderr, "DEBUG: Event missing or invalid 'created_at' field\r\n");
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    // Look for expiration in tags
    cJSON* tags = cJSON_GetObjectItem(event, "tags");
    if (!tags || !cJSON_IsArray(tags)) {
        fprintf(stderr, "DEBUG: Event missing or invalid 'tags' field\r\n");
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    time_t expiration = 0;
    int found_method = 0;
    int found_hash = 0;
    
    // Parse tags for 't' (method), 'x' (hash), and 'expiration'
    cJSON* tag = NULL;
    cJSON_ArrayForEach(tag, tags) {
        if (!cJSON_IsArray(tag)) continue;
        
        cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
        if (!tag_name || !cJSON_IsString(tag_name)) continue;
        
        const char* tag_name_str = cJSON_GetStringValue(tag_name);
        
        if (strcmp(tag_name_str, "t") == 0) {
            // Method tag
            cJSON* method_value = cJSON_GetArrayItem(tag, 1);
            if (method_value && cJSON_IsString(method_value)) {
                const char* event_method = cJSON_GetStringValue(method_value);
                if (strcmp(event_method, method) == 0) {
                    found_method = 1;
                    fprintf(stderr, "DEBUG: Found matching method tag: %s\r\n", event_method);
                }
            }
        } else if (strcmp(tag_name_str, "x") == 0) {
            // Hash tag
            cJSON* hash_value = cJSON_GetArrayItem(tag, 1);
            if (hash_value && cJSON_IsString(hash_value)) {
                const char* event_hash = cJSON_GetStringValue(hash_value);
                if (expected_hash && strcmp(event_hash, expected_hash) == 0) {
                    found_hash = 1;
                    fprintf(stderr, "DEBUG: Found matching hash tag: %s\r\n", event_hash);
                }
            }
        } else if (strcmp(tag_name_str, "expiration") == 0) {
            // Expiration tag
            cJSON* exp_value = cJSON_GetArrayItem(tag, 1);
            if (exp_value && cJSON_IsString(exp_value)) {
                expiration = (time_t)atol(cJSON_GetStringValue(exp_value));
                fprintf(stderr, "DEBUG: Found expiration tag: %ld\r\n", expiration);
            }
        }
    }
    
    // Check if method matches (required)
    if (!found_method) {
        fprintf(stderr, "DEBUG: Event missing or invalid method tag\r\n");
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    // Check if hash matches (if provided)
    if (expected_hash && !found_hash) {
        fprintf(stderr, "DEBUG: Event hash doesn't match expected hash\r\n");
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    // Check expiration
    time_t now = time(NULL);
    if (expiration > 0 && now > expiration) {
        fprintf(stderr, "DEBUG: Event expired (now: %ld, exp: %ld)\r\n", now, expiration);
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    
    fprintf(stderr, "DEBUG: Blossom event validation passed\r\n");
    return NOSTR_SUCCESS;
}

// Forward declarations for detailed validation functions
int detailed_structure_validation(cJSON* event);
int detailed_signature_validation(cJSON* event);
void analyze_event_fields(cJSON* event);
void hex_dump(const char* label, const unsigned char* data, size_t len);

/**
 * Detailed structure validation with step-by-step logging
 */
int detailed_structure_validation(cJSON* event) {
    LOG_DIVIDER();
    LOG_STEP("STRUCT-1", "Starting detailed structure validation");
    
    if (!event || !cJSON_IsObject(event)) {
        LOG_ERROR("Event is null or not a JSON object");
        return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
    }
    LOG_SUCCESS("Event is valid JSON object");
    
    // Check each required field existence
    LOG_STEP("STRUCT-2", "Checking required field existence");
    const char* required_fields[] = {"id", "pubkey", "created_at", "kind", "tags", "content", "sig"};
    for (int i = 0; i < 7; i++) {
        cJSON* field = cJSON_GetObjectItem(event, required_fields[i]);
        if (!field) {
            LOG_ERROR("Missing required field: %s", required_fields[i]);
            return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
        }
        LOG_SUCCESS("Field '%s' exists", required_fields[i]);
    }
    
    // Get all fields for detailed validation
    cJSON* id_item = cJSON_GetObjectItem(event, "id");
    cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
    cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
    cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
    cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
    cJSON* content_item = cJSON_GetObjectItem(event, "content");
    cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
    
    // Validate field types
    LOG_STEP("STRUCT-3", "Validating field types");
    if (!cJSON_IsString(id_item)) {
        LOG_ERROR("Field 'id' is not a string (type: %d)", id_item->type);
        return NOSTR_ERROR_EVENT_INVALID_ID;
    }
    LOG_SUCCESS("Field 'id' is string");
    
    if (!cJSON_IsString(pubkey_item)) {
        LOG_ERROR("Field 'pubkey' is not a string (type: %d)", pubkey_item->type);
        return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
    }
    LOG_SUCCESS("Field 'pubkey' is string");
    
    if (!cJSON_IsNumber(created_at_item)) {
        LOG_ERROR("Field 'created_at' is not a number (type: %d)", created_at_item->type);
        return NOSTR_ERROR_EVENT_INVALID_CREATED_AT;
    }
    LOG_SUCCESS("Field 'created_at' is number");
    
    if (!cJSON_IsNumber(kind_item)) {
        LOG_ERROR("Field 'kind' is not a number (type: %d)", kind_item->type);
        return NOSTR_ERROR_EVENT_INVALID_KIND;
    }
    LOG_SUCCESS("Field 'kind' is number");
    
    if (!cJSON_IsArray(tags_item)) {
        LOG_ERROR("Field 'tags' is not an array (type: %d)", tags_item->type);
        return NOSTR_ERROR_EVENT_INVALID_TAGS;
    }
    LOG_SUCCESS("Field 'tags' is array");
    
    if (!cJSON_IsString(content_item)) {
        LOG_ERROR("Field 'content' is not a string (type: %d)", content_item->type);
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    LOG_SUCCESS("Field 'content' is string");
    
    if (!cJSON_IsString(sig_item)) {
        LOG_ERROR("Field 'sig' is not a string (type: %d)", sig_item->type);
        return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
    }
    LOG_SUCCESS("Field 'sig' is string");
    
    // Validate hex string lengths
    LOG_STEP("STRUCT-4", "Validating hex string lengths");
    const char* id_str = cJSON_GetStringValue(id_item);
    const char* pubkey_str = cJSON_GetStringValue(pubkey_item);
    const char* sig_str = cJSON_GetStringValue(sig_item);
    
    LOG_INFO("ID string: '%s' (length: %zu)", id_str, id_str ? strlen(id_str) : 0);
    if (!id_str || strlen(id_str) != 64) {
        LOG_ERROR("ID string invalid length (expected 64, got %zu)", id_str ? strlen(id_str) : 0);
        return NOSTR_ERROR_EVENT_INVALID_ID;
    }
    LOG_SUCCESS("ID string length is correct (64 chars)");
    
    LOG_INFO("Pubkey string: '%s' (length: %zu)", pubkey_str, pubkey_str ? strlen(pubkey_str) : 0);
    if (!pubkey_str || strlen(pubkey_str) != 64) {
        LOG_ERROR("Pubkey string invalid length (expected 64, got %zu)", pubkey_str ? strlen(pubkey_str) : 0);
        return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
    }
    LOG_SUCCESS("Pubkey string length is correct (64 chars)");
    
    LOG_INFO("Signature string: '%s' (length: %zu)", sig_str, sig_str ? strlen(sig_str) : 0);
    if (!sig_str || strlen(sig_str) != 128) {
        LOG_ERROR("Signature string invalid length (expected 128, got %zu)", sig_str ? strlen(sig_str) : 0);
        return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
    }
    LOG_SUCCESS("Signature string length is correct (128 chars)");
    
    // Validate hex characters
    LOG_STEP("STRUCT-5", "Validating hex characters");
    LOG_INFO("Checking ID hex characters...");
    for (int i = 0; i < 64; i++) {
        char c = id_str[i];
        if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
            LOG_ERROR("Invalid hex character in ID at position %d: '%c' (0x%02x)", i, c, (unsigned char)c);
            return NOSTR_ERROR_EVENT_INVALID_ID;
        }
    }
    LOG_SUCCESS("ID hex characters are valid (lowercase)");
    
    LOG_INFO("Checking pubkey hex characters...");
    for (int i = 0; i < 64; i++) {
        char c = pubkey_str[i];
        if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
            LOG_ERROR("Invalid hex character in pubkey at position %d: '%c' (0x%02x)", i, c, (unsigned char)c);
            return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
        }
    }
    LOG_SUCCESS("Pubkey hex characters are valid (lowercase)");
    
    LOG_INFO("Checking signature hex characters...");
    for (int i = 0; i < 128; i++) {
        char c = sig_str[i];
        if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
            LOG_ERROR("Invalid hex character in signature at position %d: '%c' (0x%02x)", i, c, (unsigned char)c);
            return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
        }
    }
    LOG_SUCCESS("Signature hex characters are valid (lowercase)");
    
    // Validate timestamp
    LOG_STEP("STRUCT-6", "Validating timestamp");
    double created_at = cJSON_GetNumberValue(created_at_item);
    LOG_INFO("Created_at timestamp: %.0f", created_at);
    if (created_at < 0) {
        LOG_ERROR("Invalid timestamp (negative): %.0f", created_at);
        return NOSTR_ERROR_EVENT_INVALID_CREATED_AT;
    }
    
    // Convert to human readable time
    time_t timestamp = (time_t)created_at;
    char time_str[100];
    struct tm* tm_info = gmtime(&timestamp);
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S UTC", tm_info);
    LOG_SUCCESS("Timestamp is valid: %s", time_str);
    
    // Validate kind
    LOG_STEP("STRUCT-7", "Validating kind");
    double kind = cJSON_GetNumberValue(kind_item);
    LOG_INFO("Event kind: %.0f", kind);
    if (kind < 0 || kind > 65535 || kind != (int)kind) {
        LOG_ERROR("Invalid kind value: %.0f (must be integer 0-65535)", kind);
        return NOSTR_ERROR_EVENT_INVALID_KIND;
    }
    LOG_SUCCESS("Kind is valid: %d", (int)kind);
    
    // Validate tags array structure
    LOG_STEP("STRUCT-8", "Validating tags array structure");
    int tag_count = cJSON_GetArraySize(tags_item);
    LOG_INFO("Tags array has %d elements", tag_count);
    
    cJSON* tag_item;
    int tag_index = 0;
    cJSON_ArrayForEach(tag_item, tags_item) {
        if (!cJSON_IsArray(tag_item)) {
            LOG_ERROR("Tag at index %d is not an array (type: %d)", tag_index, tag_item->type);
            return NOSTR_ERROR_EVENT_INVALID_TAGS;
        }
        
        int tag_element_count = cJSON_GetArraySize(tag_item);
        LOG_INFO("Tag[%d] has %d elements", tag_index, tag_element_count);
        
        cJSON* tag_element;
        int element_index = 0;
        cJSON_ArrayForEach(tag_element, tag_item) {
            if (!cJSON_IsString(tag_element)) {
                LOG_ERROR("Tag[%d][%d] is not a string (type: %d)", tag_index, element_index, tag_element->type);
                return NOSTR_ERROR_EVENT_INVALID_TAGS;
            }
            const char* tag_value = cJSON_GetStringValue(tag_element);
            LOG_INFO("Tag[%d][%d]: '%s'", tag_index, element_index, tag_value);
            element_index++;
        }
        tag_index++;
    }
    LOG_SUCCESS("Tags array structure is valid");
    
    // Validate content
    LOG_STEP("STRUCT-9", "Validating content");
    const char* content_str = cJSON_GetStringValue(content_item);
    LOG_INFO("Content: '%s' (length: %zu)", content_str, content_str ? strlen(content_str) : 0);
    LOG_SUCCESS("Content is valid string");
    
    LOG_SUCCESS("Structure validation completed successfully");
    return NOSTR_SUCCESS;
}

/**
 * Detailed signature validation with step-by-step logging
 */
int detailed_signature_validation(cJSON* event) {
    LOG_DIVIDER();
    LOG_STEP("CRYPTO-1", "Starting detailed signature validation");
    
    if (!event) {
        LOG_ERROR("Event is null");
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    // Get event fields
    cJSON* id_item = cJSON_GetObjectItem(event, "id");
    cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
    cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
    cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
    cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
    cJSON* content_item = cJSON_GetObjectItem(event, "content");
    cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
    
    if (!id_item || !pubkey_item || !created_at_item || !kind_item ||
        !tags_item || !content_item || !sig_item) {
        LOG_ERROR("Missing required fields for signature validation");
        return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
    }
    
    // Create serialization array
    LOG_STEP("CRYPTO-2", "Creating serialization array");
    cJSON* serialize_array = cJSON_CreateArray();
    if (!serialize_array) {
        LOG_ERROR("Failed to create serialization array");
        return NOSTR_ERROR_MEMORY_FAILED;
    }
    
    cJSON_AddItemToArray(serialize_array, cJSON_CreateNumber(0));
    cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(pubkey_item, 1));
    cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(created_at_item, 1));
    cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(kind_item, 1));
    cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(tags_item, 1));
    cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(content_item, 1));
    
    LOG_SUCCESS("Serialization array created");
    
    // Convert to JSON string
    LOG_STEP("CRYPTO-3", "Converting to JSON string");
    char* serialize_string = cJSON_PrintUnformatted(serialize_array);
    cJSON_Delete(serialize_array);
    
    if (!serialize_string) {
        LOG_ERROR("Failed to serialize array to JSON string");
        return NOSTR_ERROR_MEMORY_FAILED;
    }
    
    LOG_SUCCESS("JSON serialization string created");
    LOG_INFO("Serialization string (length %zu): %s", strlen(serialize_string), serialize_string);
    
    // Hash the serialized event
    LOG_STEP("CRYPTO-4", "Computing SHA256 hash");
    unsigned char event_hash[32];
    if (nostr_sha256((const unsigned char*)serialize_string, strlen(serialize_string), event_hash) != 0) {
        LOG_ERROR("SHA256 hashing failed");
        free(serialize_string);
        return NOSTR_ERROR_CRYPTO_FAILED;
    }
    
    LOG_SUCCESS("SHA256 hash computed");
    hex_dump("Event hash", event_hash, 32);
    
    // Convert hash to hex for event ID verification
    LOG_STEP("CRYPTO-5", "Verifying event ID");
    char calculated_id[65];
    nostr_bytes_to_hex(event_hash, 32, calculated_id);
    
    const char* provided_id = cJSON_GetStringValue(id_item);
    LOG_INFO("Calculated ID: %s", calculated_id);
    LOG_INFO("Provided ID:   %s", provided_id);
    
    if (!provided_id || strcmp(calculated_id, provided_id) != 0) {
        LOG_ERROR("Event ID mismatch!");
        LOG_ERROR("  Expected: %s", calculated_id);
        LOG_ERROR("  Got:      %s", provided_id ? provided_id : "NULL");
        free(serialize_string);
        return NOSTR_ERROR_EVENT_INVALID_ID;
    }
    LOG_SUCCESS("Event ID verification passed");
    
    // Prepare signature verification
    LOG_STEP("CRYPTO-6", "Preparing signature verification");
    const char* pubkey_str = cJSON_GetStringValue(pubkey_item);
    const char* sig_str = cJSON_GetStringValue(sig_item);
    
    if (!pubkey_str || !sig_str) {
        LOG_ERROR("Missing pubkey or signature strings");
        free(serialize_string);
        return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
    }
    
    // Convert hex strings to bytes
    LOG_STEP("CRYPTO-7", "Converting hex strings to bytes");
    unsigned char pubkey_bytes[32];
    unsigned char sig_bytes[64];
    
    if (nostr_hex_to_bytes(pubkey_str, pubkey_bytes, 32) != 0) {
        LOG_ERROR("Failed to convert pubkey hex to bytes");
        free(serialize_string);
        return NOSTR_ERROR_CRYPTO_FAILED;
    }
    LOG_SUCCESS("Pubkey hex converted to bytes");
    hex_dump("Pubkey bytes", pubkey_bytes, 32);
    
    if (nostr_hex_to_bytes(sig_str, sig_bytes, 64) != 0) {
        LOG_ERROR("Failed to convert signature hex to bytes");
        free(serialize_string);
        return NOSTR_ERROR_CRYPTO_FAILED;
    }
    LOG_SUCCESS("Signature hex converted to bytes");
    hex_dump("Signature bytes", sig_bytes, 64);
    
    // Verify signature using nostr_core_lib function (avoiding direct secp256k1 calls)
    LOG_STEP("CRYPTO-8", "Verifying signature using nostr_verify_event_signature()");
    
    // Create a temporary event structure for verification
    cJSON* temp_event = cJSON_CreateObject();
    if (!temp_event) {
        LOG_ERROR("Failed to create temporary event for verification");
        free(serialize_string);
        return NOSTR_ERROR_MEMORY_FAILED;
    }
    
    // Copy all required fields to temp event
    cJSON_AddItemToObject(temp_event, "id", cJSON_Duplicate(id_item, 1));
    cJSON_AddItemToObject(temp_event, "pubkey", cJSON_Duplicate(pubkey_item, 1));
    cJSON_AddItemToObject(temp_event, "created_at", cJSON_Duplicate(created_at_item, 1));
    cJSON_AddItemToObject(temp_event, "kind", cJSON_Duplicate(kind_item, 1));
    cJSON_AddItemToObject(temp_event, "tags", cJSON_Duplicate(tags_item, 1));
    cJSON_AddItemToObject(temp_event, "content", cJSON_Duplicate(content_item, 1));
    cJSON_AddItemToObject(temp_event, "sig", cJSON_Duplicate(sig_item, 1));
    
    LOG_INFO("Calling nostr_verify_event_signature() for detailed crypto validation");
    int crypto_verify_result = nostr_verify_event_signature(temp_event);
    LOG_INFO("nostr_verify_event_signature returned: %d (%s)",
             crypto_verify_result, nostr_strerror(crypto_verify_result));
    
    cJSON_Delete(temp_event);
    
    if (crypto_verify_result != NOSTR_SUCCESS) {
        LOG_ERROR("Signature verification FAILED!");
        LOG_ERROR("nostr_verify_event_signature returned error: %d (%s)",
                  crypto_verify_result, nostr_strerror(crypto_verify_result));
        free(serialize_string);
        return crypto_verify_result;
    }
    
    LOG_SUCCESS("Signature verification PASSED using nostr_core_lib!");
    free(serialize_string);
    return NOSTR_SUCCESS;
}

/**
 * Analyze event fields in detail
 */
void analyze_event_fields(cJSON* event) {
    LOG_DIVIDER();
    LOG_STEP("ANALYZE-1", "Analyzing event field details");
    
    cJSON* field;
    cJSON_ArrayForEach(field, event) {
        if (field->string) {
            LOG_INFO("Field '%s':", field->string);
            if (cJSON_IsString(field)) {
                const char* value = cJSON_GetStringValue(field);
                LOG_INFO("  Type: String");
                LOG_INFO("  Value: '%s'", value);
                LOG_INFO("  Length: %zu", value ? strlen(value) : 0);
            } else if (cJSON_IsNumber(field)) {
                double value = cJSON_GetNumberValue(field);
                LOG_INFO("  Type: Number");
                LOG_INFO("  Value: %.0f", value);
            } else if (cJSON_IsArray(field)) {
                int size = cJSON_GetArraySize(field);
                LOG_INFO("  Type: Array");
                LOG_INFO("  Size: %d", size);
            } else {
                LOG_INFO("  Type: Other (%d)", field->type);
            }
        }
    }
}

/**
 * Print hex dump of binary data
 */
void hex_dump(const char* label, const unsigned char* data, size_t len) {
    LOG_INFO("%s (%zu bytes):", label, len);
    for (size_t i = 0; i < len; i += 16) {
        fprintf(stderr, "  %04zx: ", i);
        for (size_t j = 0; j < 16; j++) {
            if (i + j < len) {
                fprintf(stderr, "%02x ", data[i + j]);
            } else {
                fprintf(stderr, "   ");
            }
        }
        fprintf(stderr, " |");
        for (size_t j = 0; j < 16 && i + j < len; j++) {
            unsigned char c = data[i + j];
            fprintf(stderr, "%c", (c >= 32 && c <= 126) ? c : '.');
        }
        fprintf(stderr, "|\n");
    }
}

// Main authentication function with comprehensive step-by-step logging
int authenticate_request(const char* auth_header, const char* method, const char* file_hash) {
    LOG_DIVIDER();
    LOG_STEP("SERVER-1", "Starting server-style authentication (mirroring test_auth_debug.c)");
    
    if (!auth_header) {
        LOG_ERROR("No authorization header provided");
        return NOSTR_ERROR_INVALID_INPUT;
    }
    
    LOG_INFO("Server-style auth called with method: %s, hash: %s",
             method ? method : "null", file_hash ? file_hash : "null");
    
    // Parse authorization header (same as server)
    char event_json[4096];
    LOG_STEP("SERVER-2", "Calling parse_authorization_header");
    int parse_result = parse_authorization_header(auth_header, event_json, sizeof(event_json));
    if (parse_result != NOSTR_SUCCESS) {
        LOG_ERROR("Authorization header parsing failed: %d (%s)", parse_result, nostr_strerror(parse_result));
        return parse_result;
    }
    LOG_SUCCESS("parse_authorization_header succeeded");
    
    // Parse JSON event (same as server)
    LOG_STEP("SERVER-3", "Calling cJSON_Parse on JSON string");
    LOG_INFO("JSON to parse: %s", event_json);
    cJSON* event = cJSON_Parse(event_json);
    if (!event) {
        LOG_ERROR("Failed to parse JSON event with cJSON_Parse");
        return NOSTR_ERROR_EVENT_INVALID_CONTENT;
    }
    LOG_SUCCESS("cJSON_Parse succeeded, event parsed");
    
    // Print complete parsed JSON like server does
    char* parsed_json_str = cJSON_Print(event);
    LOG_INFO("Parsed JSON: %s", parsed_json_str ? parsed_json_str : "NULL");
    if (parsed_json_str) free(parsed_json_str);
    
    // Debug: Print event fields before validation (same as server)
    cJSON* id_json = cJSON_GetObjectItem(event, "id");
    cJSON* pubkey_json = cJSON_GetObjectItem(event, "pubkey");
    cJSON* sig_json = cJSON_GetObjectItem(event, "sig");
    cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
    cJSON* created_at_json = cJSON_GetObjectItem(event, "created_at");
    
    LOG_STEP("SERVER-4", "Event fields before validation");
    LOG_INFO("  id: %s", id_json && cJSON_IsString(id_json) ? cJSON_GetStringValue(id_json) : "MISSING/INVALID");
    LOG_INFO("  pubkey: %s", pubkey_json && cJSON_IsString(pubkey_json) ? cJSON_GetStringValue(pubkey_json) : "MISSING/INVALID");
    LOG_INFO("  sig: %s", sig_json && cJSON_IsString(sig_json) ? cJSON_GetStringValue(sig_json) : "MISSING/INVALID");
    LOG_INFO("  kind: %d", kind_json && cJSON_IsNumber(kind_json) ? (int)cJSON_GetNumberValue(kind_json) : -999);
    LOG_INFO("  created_at: %ld", created_at_json && cJSON_IsNumber(created_at_json) ? (long)cJSON_GetNumberValue(created_at_json) : -999);
    
    // Detailed pubkey analysis (same as server)
    if (pubkey_json && cJSON_IsString(pubkey_json)) {
        const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
        LOG_STEP("SERVER-5", "Detailed pubkey analysis");
        LOG_INFO("  Pubkey: %s", pubkey_str ? pubkey_str : "NULL");
        LOG_INFO("  Length: %zu", pubkey_str ? strlen(pubkey_str) : 0);
        if (pubkey_str && strlen(pubkey_str) == 64) {
            LOG_INFO("  Character analysis (first 10): ");
            for (int i = 0; i < 10; i++) {
                char c = pubkey_str[i];
                fprintf(stderr, "%c(0x%02x) ", c, (unsigned char)c);
            }
            fprintf(stderr, "\n");
        }
    }
    
    // Pre-validation pubkey analysis (same as server)
    LOG_STEP("SERVER-6", "Pre-validation pubkey analysis");
    if (pubkey_json && cJSON_IsString(pubkey_json)) {
        const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
        LOG_INFO("  Pubkey: %s", pubkey_str ? pubkey_str : "NULL");
        LOG_INFO("  Length: %zu", pubkey_str ? strlen(pubkey_str) : 0);
        if (pubkey_str && strlen(pubkey_str) == 64) {
            LOG_INFO("  Character analysis (first 10): ");
            for (int i = 0; i < 10; i++) {
                char c = pubkey_str[i];
                fprintf(stderr, "%c(%d) ", c, (int)c);
            }
            fprintf(stderr, "\n");
            LOG_INFO("  Character validation test: ");
            int valid_chars = 1;
            for (int i = 0; i < 64; i++) {
                char c = pubkey_str[i];
                if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
                    fprintf(stderr, "INVALID at pos %d: %c(%d) ", i, c, (int)c);
                    valid_chars = 0;
                }
            }
            if (valid_chars) {
                fprintf(stderr, "ALL VALID (lowercase hex)\n");
            } else {
                fprintf(stderr, "\n");
            }
        }
    }
    
    // Detailed validation analysis (same as server)
    LOG_STEP("SERVER-7", "Starting detailed validation analysis");
    
    // Test structure validation first (same as server)
    LOG_INFO("Testing structure validation...");
    int structure_result = nostr_validate_event_structure(event);
    LOG_INFO("nostr_validate_event_structure returned: %d (%s)",
           structure_result, nostr_strerror(structure_result));
    
    // EMERGENCY DEBUG: Write structure validation result to file
    FILE* debug_file = fopen("debug_validation.log", "a");
    if (debug_file) {
        fprintf(debug_file, "=== STRUCTURE VALIDATION DEBUG ===\n");
        fprintf(debug_file, "nostr_validate_event_structure result: %d (%s)\n",
                structure_result, nostr_strerror(structure_result));
        if (structure_result != NOSTR_SUCCESS) {
            fprintf(debug_file, "STRUCTURE VALIDATION FAILED!\n");
            // Log the event JSON for debugging
            char* event_str = cJSON_Print(event);
            if (event_str) {
                fprintf(debug_file, "Event JSON: %s\n", event_str);
                free(event_str);
            }
        }
        fprintf(debug_file, "=== END STRUCTURE DEBUG ===\n\n");
        fclose(debug_file);
    }
    
    if (structure_result != NOSTR_SUCCESS) {
        LOG_ERROR("STRUCTURE validation failed!");
        cJSON_Delete(event);
        return structure_result;
    }
    LOG_SUCCESS("Structure validation PASSED");
    
    // Test crypto validation separately (same as server)
    LOG_INFO("Testing cryptographic verification...");
    int crypto_result = nostr_verify_event_signature(event);
    LOG_INFO("nostr_verify_event_signature returned: %d (%s)",
           crypto_result, nostr_strerror(crypto_result));
    
    // EMERGENCY DEBUG: Write crypto validation result to file
    FILE* debug_file2 = fopen("debug_validation.log", "a");
    if (debug_file2) {
        fprintf(debug_file2, "=== CRYPTO VALIDATION DEBUG ===\n");
        fprintf(debug_file2, "nostr_verify_event_signature result: %d (%s)\n",
                crypto_result, nostr_strerror(crypto_result));
        if (crypto_result != NOSTR_SUCCESS) {
            fprintf(debug_file2, "CRYPTO VALIDATION FAILED!\n");
            if (pubkey_json && cJSON_IsString(pubkey_json)) {
                const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
                fprintf(debug_file2, "Failed pubkey: %s (length: %zu)\n",
                       pubkey_str ? pubkey_str : "NULL", pubkey_str ? strlen(pubkey_str) : 0);
            }
        }
        fprintf(debug_file2, "=== END CRYPTO DEBUG ===\n\n");
        fclose(debug_file2);
    }
    
    if (crypto_result != NOSTR_SUCCESS) {
        LOG_ERROR("CRYPTO verification failed!");
        if (pubkey_json && cJSON_IsString(pubkey_json)) {
            const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
            LOG_ERROR("Failed pubkey: %s (length: %zu)",
                   pubkey_str ? pubkey_str : "NULL", pubkey_str ? strlen(pubkey_str) : 0);
        }
        cJSON_Delete(event);
        return crypto_result;
    }
    LOG_SUCCESS("Crypto verification PASSED");
    
    // Finally test complete validation (same as server)
    LOG_INFO("Testing complete validation...");
    int validation_result = nostr_validate_event(event);
    LOG_INFO("nostr_validate_event returned: %d (%s)",
           validation_result, nostr_strerror(validation_result));
    
    // EMERGENCY DEBUG: Write complete validation result to file
    FILE* debug_file3 = fopen("debug_validation.log", "a");
    if (debug_file3) {
        fprintf(debug_file3, "=== COMPLETE VALIDATION DEBUG ===\n");
        fprintf(debug_file3, "nostr_validate_event result: %d (%s)\n",
                validation_result, nostr_strerror(validation_result));
        if (validation_result != NOSTR_SUCCESS) {
            fprintf(debug_file3, "COMPLETE VALIDATION FAILED!\n");
            if (pubkey_json && cJSON_IsString(pubkey_json)) {
                const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
                fprintf(debug_file3, "Pubkey length: %zu, value: %s\n",
                       pubkey_str ? strlen(pubkey_str) : 0, pubkey_str ? pubkey_str : "NULL");
            }
        }
        fprintf(debug_file3, "=== END COMPLETE DEBUG ===\n\n");
        fclose(debug_file3);
    }
    
    if (validation_result != NOSTR_SUCCESS) {
        LOG_ERROR("COMPLETE validation failed: %d (%s)",
               validation_result, nostr_strerror(validation_result));
        
        // Additional debug: Check specific validation issues (same as server)
        if (pubkey_json && cJSON_IsString(pubkey_json)) {
            const char* pubkey_str = cJSON_GetStringValue(pubkey_json);
            LOG_ERROR("Pubkey length: %zu, value: %s",
                   pubkey_str ? strlen(pubkey_str) : 0, pubkey_str ? pubkey_str : "NULL");
        }
        
        cJSON_Delete(event);
        return validation_result;
    }
    LOG_SUCCESS("Complete validation PASSED");
    
    // Run our detailed validations for additional debugging
    LOG_STEP("SERVER-8", "Running detailed structure validation");
    int detailed_struct_result = detailed_structure_validation(event);
    if (detailed_struct_result != NOSTR_SUCCESS) {
        LOG_ERROR("Detailed structure validation failed: %d (%s)", detailed_struct_result, nostr_strerror(detailed_struct_result));
        cJSON_Delete(event);
        return detailed_struct_result;
    }
    LOG_SUCCESS("Detailed structure validation PASSED");
    
    LOG_STEP("SERVER-9", "Running detailed signature validation");
    int detailed_crypto_result = detailed_signature_validation(event);
    if (detailed_crypto_result != NOSTR_SUCCESS) {
        LOG_ERROR("Detailed signature validation failed: %d (%s)", detailed_crypto_result, nostr_strerror(detailed_crypto_result));
        cJSON_Delete(event);
        return detailed_crypto_result;
    }
    LOG_SUCCESS("Detailed signature validation PASSED");
    
    // Analyze event fields
    analyze_event_fields(event);
    
    // Validate Blossom-specific requirements
    LOG_STEP("SERVER-10", "Validating Blossom-specific requirements");
    int blossom_result = validate_blossom_event(event, file_hash, method);
    if (blossom_result != NOSTR_SUCCESS) {
        LOG_ERROR("Blossom event validation failed: %d (%s)", blossom_result, nostr_strerror(blossom_result));
        cJSON_Delete(event);
        return blossom_result;
    }
    LOG_SUCCESS("Blossom event validation PASSED");
    
    cJSON_Delete(event);
    LOG_SUCCESS("Server-style authentication successful, returning NOSTR_SUCCESS");
    return NOSTR_SUCCESS;
}

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//             AUTHENTICATION RULES SYSTEM (4.1.2)
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

// Authentication rule result structure
typedef struct {
    int allowed;                // 0 = denied, 1 = allowed
    char reason[256];          // Human-readable reason
    int rule_id;               // Rule ID that made the decision (0 if no rule)
    int priority;              // Priority of the rule that matched
} auth_rule_result_t;

// Check if authentication rules system is enabled
int auth_rules_enabled(void) {
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc, enabled = 0;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        fprintf(stderr, "DEBUG: Database open failed in auth_rules_enabled: %s\r\n", sqlite3_errmsg(db));
        return 0; // Disable rules if can't check database
    }
    
    const char* sql = "SELECT value FROM server_config WHERE key = 'auth_rules_enabled'";
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc == SQLITE_OK) {
        rc = sqlite3_step(stmt);
        if (rc == SQLITE_ROW) {
            const char* value = (const char*)sqlite3_column_text(stmt, 0);
            enabled = (value && strcmp(value, "true") == 0) ? 1 : 0;
        }
        sqlite3_finalize(stmt);
    }
    sqlite3_close(db);
    
    return enabled;
}

// Check pubkey whitelist rule
int check_pubkey_whitelist(const char* pubkey, const char* operation, auth_rule_result_t* result) {
    if (!pubkey || !operation || !result) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    const char* sql = "SELECT id, priority, description FROM auth_rules "
                      "WHERE rule_type = 'pubkey_whitelist' AND rule_target = ? "
                      "AND (operation = ? OR operation = '*') AND enabled = 1 "
                      "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now')) "
                      "ORDER BY priority ASC, created_at ASC LIMIT 1";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, operation, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        result->allowed = 1;
        result->rule_id = sqlite3_column_int(stmt, 0);
        result->priority = sqlite3_column_int(stmt, 1);
        const char* description = (const char*)sqlite3_column_text(stmt, 2);
        snprintf(result->reason, sizeof(result->reason), 
                 "Allowed by whitelist rule: %s", description ? description : "pubkey whitelisted");
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return 1;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

// Check pubkey blacklist rule
int check_pubkey_blacklist(const char* pubkey, const char* operation, auth_rule_result_t* result) {
    if (!pubkey || !operation || !result) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    const char* sql = "SELECT id, priority, description FROM auth_rules "
                      "WHERE rule_type = 'pubkey_blacklist' AND rule_target = ? "
                      "AND (operation = ? OR operation = '*') AND enabled = 1 "
                      "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now')) "
                      "ORDER BY priority ASC, created_at ASC LIMIT 1";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, operation, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        result->allowed = 0;
        result->rule_id = sqlite3_column_int(stmt, 0);
        result->priority = sqlite3_column_int(stmt, 1);
        const char* description = (const char*)sqlite3_column_text(stmt, 2);
        snprintf(result->reason, sizeof(result->reason), 
                 "Denied by blacklist rule: %s", description ? description : "pubkey blacklisted");
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return 1;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

// Check hash blacklist rule
int check_hash_blacklist(const char* hash, const char* operation, auth_rule_result_t* result) {
    if (!hash || !operation || !result) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    const char* sql = "SELECT id, priority, description FROM auth_rules "
                      "WHERE rule_type = 'hash_blacklist' AND rule_target = ? "
                      "AND (operation = ? OR operation = '*') AND enabled = 1 "
                      "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now')) "
                      "ORDER BY priority ASC, created_at ASC LIMIT 1";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, hash, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, operation, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        result->allowed = 0;
        result->rule_id = sqlite3_column_int(stmt, 0);
        result->priority = sqlite3_column_int(stmt, 1);
        const char* description = (const char*)sqlite3_column_text(stmt, 2);
        snprintf(result->reason, sizeof(result->reason), 
                 "Denied by hash blacklist rule: %s", description ? description : "hash blacklisted");
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return 1;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

// Check MIME type whitelist rule
int check_mime_type_whitelist(const char* mime_type, const char* operation, auth_rule_result_t* result) {
    if (!mime_type || !operation || !result) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    // Check for exact match or wildcard patterns (e.g., "image/*")
    const char* sql = "SELECT id, priority, description FROM auth_rules "
                      "WHERE rule_type = 'mime_type_whitelist' "
                      "AND (rule_target = ? OR (rule_target LIKE '%/*' AND ? LIKE REPLACE(rule_target, '*', '%'))) "
                      "AND (operation = ? OR operation = '*') AND enabled = 1 "
                      "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now')) "
                      "ORDER BY priority ASC, created_at ASC LIMIT 1";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, mime_type, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, mime_type, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 3, operation, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        result->allowed = 1;
        result->rule_id = sqlite3_column_int(stmt, 0);
        result->priority = sqlite3_column_int(stmt, 1);
        const char* description = (const char*)sqlite3_column_text(stmt, 2);
        snprintf(result->reason, sizeof(result->reason), 
                 "Allowed by MIME type whitelist: %s", description ? description : "MIME type whitelisted");
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return 1;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

// Check MIME type blacklist rule
int check_mime_type_blacklist(const char* mime_type, const char* operation, auth_rule_result_t* result) {
    if (!mime_type || !operation || !result) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    // Check for exact match or wildcard patterns (e.g., "application/*")
    const char* sql = "SELECT id, priority, description FROM auth_rules "
                      "WHERE rule_type = 'mime_type_blacklist' "
                      "AND (rule_target = ? OR (rule_target LIKE '%/*' AND ? LIKE REPLACE(rule_target, '*', '%'))) "
                      "AND (operation = ? OR operation = '*') AND enabled = 1 "
                      "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now')) "
                      "ORDER BY priority ASC, created_at ASC LIMIT 1";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, mime_type, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, mime_type, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 3, operation, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        result->allowed = 0;
        result->rule_id = sqlite3_column_int(stmt, 0);
        result->priority = sqlite3_column_int(stmt, 1);
        const char* description = (const char*)sqlite3_column_text(stmt, 2);
        snprintf(result->reason, sizeof(result->reason), 
                 "Denied by MIME type blacklist: %s", description ? description : "MIME type blacklisted");
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return 1;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

// Check file size limit rule
int check_size_limit(long file_size, const char* pubkey, const char* operation, auth_rule_result_t* result) {
    if (!result || file_size < 0) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    // Check for pubkey-specific or global size limits
    const char* sql = "SELECT id, priority, rule_value, description FROM auth_rules "
                      "WHERE rule_type = 'size_limit' "
                      "AND (rule_target = ? OR rule_target = '*') "
                      "AND (operation = ? OR operation = '*') AND enabled = 1 "
                      "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now')) "
                      "ORDER BY CASE WHEN rule_target = ? THEN 0 ELSE 1 END, priority ASC, created_at ASC LIMIT 1";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, pubkey ? pubkey : "*", -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, operation, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 3, pubkey ? pubkey : "*", -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        const char* size_limit_str = (const char*)sqlite3_column_text(stmt, 2);
        long size_limit = size_limit_str ? atol(size_limit_str) : 0;
        
        if (size_limit > 0 && file_size > size_limit) {
            result->allowed = 0;
            result->rule_id = sqlite3_column_int(stmt, 0);
            result->priority = sqlite3_column_int(stmt, 1);
            const char* description = (const char*)sqlite3_column_text(stmt, 3);
            snprintf(result->reason, sizeof(result->reason), 
                     "File size %ld exceeds limit %ld: %s", 
                     file_size, size_limit, description ? description : "size limit exceeded");
            
            sqlite3_finalize(stmt);
            sqlite3_close(db);
            return 1;
        }
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//             RULE EVALUATION ENGINE (4.1.3)
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

// Cache key generation for authentication decisions
void generate_auth_cache_key(const char* pubkey, const char* operation, const char* hash, 
                            const char* mime_type, long file_size, char* cache_key, size_t key_size) {
    char temp_buffer[1024];
    snprintf(temp_buffer, sizeof(temp_buffer), "%s|%s|%s|%s|%ld", 
             pubkey ? pubkey : "", operation ? operation : "",
             hash ? hash : "", mime_type ? mime_type : "", file_size);
    
    // Generate SHA-256 hash of the key components for consistent cache keys
    unsigned char hash_bytes[32];
    if (nostr_sha256((unsigned char*)temp_buffer, strlen(temp_buffer), hash_bytes) == NOSTR_SUCCESS) {
        nostr_bytes_to_hex(hash_bytes, 32, cache_key);
        cache_key[64] = '\0';  // Ensure null termination
    } else {
        // Fallback if hashing fails
        strncpy(cache_key, temp_buffer, key_size - 1);
        cache_key[key_size - 1] = '\0';
    }
}

// Check authentication cache for previous decisions
int check_auth_cache(const char* cache_key, auth_rule_result_t* result) {
    if (!cache_key || !result) {
        return 0;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        return 0;
    }
    
    const char* sql = "SELECT allowed, rule_id, rule_reason FROM auth_cache "
                      "WHERE cache_key = ? AND expires_at > strftime('%s', 'now')";
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return 0;
    }
    
    sqlite3_bind_text(stmt, 1, cache_key, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_ROW) {
        result->allowed = sqlite3_column_int(stmt, 0);
        result->rule_id = sqlite3_column_int(stmt, 1);
        result->priority = 0; // Not stored in cache
        const char* reason = (const char*)sqlite3_column_text(stmt, 2);
        if (reason) {
            strncpy(result->reason, reason, sizeof(result->reason) - 1);
            result->reason[sizeof(result->reason) - 1] = '\0';
        }
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        fprintf(stderr, "DEBUG: Cache hit for key: %.16s... (allowed=%d)\r\n", cache_key, result->allowed);
        return 1;
    }
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

// Store authentication decision in cache
void store_auth_cache(const char* cache_key, const auth_rule_result_t* result) {
    if (!cache_key || !result) {
        return;
    }
    
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READWRITE, NULL);
    if (rc) {
        fprintf(stderr, "DEBUG: Failed to open database for caching: %s\r\n", sqlite3_errmsg(db));
        return;
    }
    
    // Get cache TTL from server config (default 5 minutes)
    int cache_ttl = 300;
    const char* ttl_sql = "SELECT value FROM server_config WHERE key = 'auth_cache_ttl'";
    rc = sqlite3_prepare_v2(db, ttl_sql, -1, &stmt, NULL);
    if (rc == SQLITE_OK) {
        rc = sqlite3_step(stmt);
        if (rc == SQLITE_ROW) {
            const char* ttl_value = (const char*)sqlite3_column_text(stmt, 0);
            if (ttl_value) {
                cache_ttl = atoi(ttl_value);
            }
        }
        sqlite3_finalize(stmt);
    }
    
    // Insert or replace cache entry
    const char* insert_sql = "INSERT OR REPLACE INTO auth_cache "
                             "(cache_key, allowed, rule_id, rule_reason, expires_at) "
                             "VALUES (?, ?, ?, ?, strftime('%s', 'now') + ?)";
    
    rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL);
    if (rc == SQLITE_OK) {
        sqlite3_bind_text(stmt, 1, cache_key, -1, SQLITE_STATIC);
        sqlite3_bind_int(stmt, 2, result->allowed);
        sqlite3_bind_int(stmt, 3, result->rule_id);
        sqlite3_bind_text(stmt, 4, result->reason, -1, SQLITE_STATIC);
        sqlite3_bind_int(stmt, 5, cache_ttl);
        
        rc = sqlite3_step(stmt);
        if (rc == SQLITE_DONE) {
            fprintf(stderr, "DEBUG: Cached auth decision for key: %.16s... (TTL=%d)\r\n", cache_key, cache_ttl);
        } else {
            fprintf(stderr, "DEBUG: Failed to cache auth decision: %s\r\n", sqlite3_errmsg(db));
        }
        sqlite3_finalize(stmt);
    }
    
    sqlite3_close(db);
}

// Main rule evaluation function
int evaluate_auth_rules(const char* pubkey, const char* operation, const char* hash, 
                       const char* mime_type, long file_size, auth_rule_result_t* result) {
    if (!result) {
        return 0;
    }
    
    // Initialize result structure
    memset(result, 0, sizeof(auth_rule_result_t));
    result->allowed = 1; // Default allow if no rules apply
    strcpy(result->reason, "No rules matched - default allow");
    
    fprintf(stderr, "DEBUG: evaluate_auth_rules called - pubkey=%s, op=%s, hash=%s, mime=%s, size=%ld\r\n",
           pubkey ? pubkey : "NULL", operation ? operation : "NULL", 
           hash ? hash : "NULL", mime_type ? mime_type : "NULL", file_size);
    
    // Check if authentication rules system is enabled
    if (!auth_rules_enabled()) {
        fprintf(stderr, "DEBUG: Authentication rules system is disabled\r\n");
        strcpy(result->reason, "Authentication rules system disabled - default allow");
        return 1;
    }
    
    // Generate cache key for this request
    char cache_key[128];
    generate_auth_cache_key(pubkey, operation, hash, mime_type, file_size, cache_key, sizeof(cache_key));
    
    // Check cache first for performance
    if (check_auth_cache(cache_key, result)) {
        fprintf(stderr, "DEBUG: Using cached authentication decision\r\n");
        return 1;
    }
    
    fprintf(stderr, "DEBUG: No cache hit - evaluating rules in priority order\r\n");
    
    // Evaluate rules in priority order (lower priority number = higher precedence)
    auth_rule_result_t rule_result;
    int highest_priority = 9999;
    int rule_matched = 0;
    
    // 1. Check pubkey blacklist first (highest security priority)
    if (pubkey && check_pubkey_blacklist(pubkey, operation, &rule_result)) {
        if (rule_result.priority < highest_priority) {
            *result = rule_result;
            highest_priority = rule_result.priority;
            rule_matched = 1;
            fprintf(stderr, "DEBUG: Pubkey blacklist rule matched (priority %d)\r\n", rule_result.priority);
        }
    }
    
    // 2. Check hash blacklist
    if (hash && check_hash_blacklist(hash, operation, &rule_result)) {
        if (rule_result.priority < highest_priority) {
            *result = rule_result;
            highest_priority = rule_result.priority;
            rule_matched = 1;
            fprintf(stderr, "DEBUG: Hash blacklist rule matched (priority %d)\r\n", rule_result.priority);
        }
    }
    
    // 3. Check MIME type blacklist
    if (mime_type && check_mime_type_blacklist(mime_type, operation, &rule_result)) {
        if (rule_result.priority < highest_priority) {
            *result = rule_result;
            highest_priority = rule_result.priority;
            rule_matched = 1;
            fprintf(stderr, "DEBUG: MIME type blacklist rule matched (priority %d)\r\n", rule_result.priority);
        }
    }
    
    // 4. Check file size limits
    if (file_size > 0 && check_size_limit(file_size, pubkey, operation, &rule_result)) {
        if (rule_result.priority < highest_priority) {
            *result = rule_result;
            highest_priority = rule_result.priority;
            rule_matched = 1;
            fprintf(stderr, "DEBUG: Size limit rule matched (priority %d)\r\n", rule_result.priority);
        }
    }
    
    // 5. Check pubkey whitelist (only matters if not already denied)
    if (pubkey && result->allowed && check_pubkey_whitelist(pubkey, operation, &rule_result)) {
        if (rule_result.priority < highest_priority) {
            *result = rule_result;
            highest_priority = rule_result.priority;
            rule_matched = 1;
            fprintf(stderr, "DEBUG: Pubkey whitelist rule matched (priority %d)\r\n", rule_result.priority);
        }
    }
    
    // 6. Check MIME type whitelist (only if not already denied)
    if (mime_type && result->allowed && check_mime_type_whitelist(mime_type, operation, &rule_result)) {
        if (rule_result.priority < highest_priority) {
            *result = rule_result;
            highest_priority = rule_result.priority;
            rule_matched = 1;
            fprintf(stderr, "DEBUG: MIME type whitelist rule matched (priority %d)\r\n", rule_result.priority);
        }
    }
    
    // Special case: If we have whitelist rules but no whitelist matched, deny by default
    if (result->allowed && pubkey) {
        sqlite3* db;
        sqlite3_stmt* stmt;
        int rc;
        
        rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
        if (rc == SQLITE_OK) {
            // Check if any pubkey whitelist rules exist for this operation
            const char* sql = "SELECT COUNT(*) FROM auth_rules "
                              "WHERE rule_type = 'pubkey_whitelist' AND enabled = 1 "
                              "AND (operation = ? OR operation = '*') "
                              "AND (expires_at IS NULL OR expires_at > strftime('%s', 'now'))";
            
            rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
            if (rc == SQLITE_OK) {
                sqlite3_bind_text(stmt, 1, operation, -1, SQLITE_STATIC);
                rc = sqlite3_step(stmt);
                if (rc == SQLITE_ROW) {
                    int whitelist_count = sqlite3_column_int(stmt, 0);
                    if (whitelist_count > 0) {
                        // Whitelist exists but didn't match - deny
                        result->allowed = 0;
                        result->rule_id = 0;
                        result->priority = 0;
                        snprintf(result->reason, sizeof(result->reason), 
                                "Denied - pubkey not in whitelist (found %d whitelist rules)", whitelist_count);
                        rule_matched = 1;
                        fprintf(stderr, "DEBUG: Denied due to whitelist policy - pubkey not whitelisted\r\n");
                    }
                }
                sqlite3_finalize(stmt);
            }
            sqlite3_close(db);
        }
    }
    
    // Cache the decision for future requests
    store_auth_cache(cache_key, result);
    
    fprintf(stderr, "DEBUG: Rule evaluation complete - allowed=%d, rule_id=%d, reason=%s\r\n",
           result->allowed, result->rule_id, result->reason);
    
    return rule_matched;
}

// Enhanced authentication function that integrates rule evaluation
int authenticate_request_with_rules(const char* auth_header, const char* method, const char* file_hash,
                                   const char* mime_type, long file_size) {
    fprintf(stderr, "DEBUG: authenticate_request_with_rules called - method: %s, file_hash: %s, mime_type: %s, file_size: %ld\r\n", 
           method ? method : "NULL", file_hash ? file_hash : "NULL", mime_type ? mime_type : "NULL", file_size);
    
    // Step 1: Basic nostr authentication (if header provided)
    const char* pubkey = NULL;
    static char pubkey_buffer[256];
    
    if (auth_header) {
        fprintf(stderr, "DEBUG: Authorization header provided, starting basic nostr authentication\r\n");
        // Parse and validate nostr event first
        int auth_result = authenticate_request(auth_header, method, file_hash);
        if (auth_result != NOSTR_SUCCESS) {
            fprintf(stderr, "DEBUG: Basic nostr authentication failed: %d (%s)\r\n", auth_result, nostr_strerror(auth_result));
            return auth_result;
        }
        fprintf(stderr, "DEBUG: Basic nostr authentication PASSED\r\n");
        
        // Extract pubkey from validated event
        char event_json[4096];
        int parse_result = parse_authorization_header(auth_header, event_json, sizeof(event_json));
        if (parse_result == NOSTR_SUCCESS) {
            cJSON* event = cJSON_Parse(event_json);
            if (event) {
                cJSON* pubkey_json = cJSON_GetObjectItem(event, "pubkey");
                if (pubkey_json && cJSON_IsString(pubkey_json)) {
                    const char* temp_pubkey = cJSON_GetStringValue(pubkey_json);
                    if (temp_pubkey) {
                        strncpy(pubkey_buffer, temp_pubkey, sizeof(pubkey_buffer)-1);
                        pubkey_buffer[sizeof(pubkey_buffer)-1] = '\0';
                        pubkey = pubkey_buffer;
                    }
                }
                cJSON_Delete(event);
            }
        }
        fprintf(stderr, "DEBUG: Extracted pubkey from auth: %s\r\n", pubkey ? pubkey : "NULL");
    } else {
        fprintf(stderr, "DEBUG: No authorization header - evaluating rules for anonymous request\r\n");
    }
    
    // Step 2: Evaluate authentication rules
    auth_rule_result_t rule_result;
    int rule_evaluated = evaluate_auth_rules(pubkey, method, file_hash, mime_type, file_size, &rule_result);
    
    if (rule_evaluated && !rule_result.allowed) {
        fprintf(stderr, "DEBUG: Request denied by authentication rules: %s\r\n", rule_result.reason);
        return NOSTR_ERROR_INVALID_INPUT; // Authentication denied by rules
    }
    
    fprintf(stderr, "DEBUG: Request allowed - nostr auth + rules passed\r\n");
    return NOSTR_SUCCESS;
}

// Enhanced error response helper functions
void send_error_response(int status_code, const char* error_type, const char* message, const char* details) {
    const char* status_text;
    switch (status_code) {
        case 400: status_text = "Bad Request"; break;
        case 401: status_text = "Unauthorized"; break;
        case 409: status_text = "Conflict"; break;
        case 413: status_text = "Payload Too Large"; break;
        case 500: status_text = "Internal Server Error"; break;
        default: status_text = "Error"; break;
    }
    
    printf("Status: %d %s\r\n", status_code, status_text);
    printf("Content-Type: application/json\r\n\r\n");
    printf("{\n");
    printf("  \"error\": \"%s\",\n", error_type);
    printf("  \"message\": \"%s\"", message);
    if (details) {
        printf(",\n  \"details\": \"%s\"", details);
    }
    printf("\n}\n");
}

void log_request(const char* method, const char* uri, const char* auth_status, int status_code) {
    time_t now = time(NULL);
    struct tm* tm_info = localtime(&now);
    char timestamp[64];
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info);
    
    // For now, log to stdout - later can be configured to log files
    fprintf(stderr, "LOG: [%s] %s %s - Auth: %s - Status: %d\r\n", 
           timestamp, method ? method : "NULL", uri ? uri : "NULL", 
           auth_status ? auth_status : "none", status_code);
}

// Handle GET /list/<pubkey> requests
void handle_list_request(const char* pubkey) {
    fprintf(stderr, "DEBUG: handle_list_request called with pubkey=%s\r\n", pubkey ? pubkey : "NULL");
    
    // Log the incoming request
    log_request("GET", "/list", "pending", 0);
    
    // Validate pubkey format (64 hex characters)
    if (!pubkey || strlen(pubkey) != 64) {
        send_error_response(400, "invalid_pubkey", "Invalid pubkey format", "Pubkey must be 64 hex characters");
        log_request("GET", "/list", "none", 400);
        return;
    }
    
    // Validate hex characters
    for (int i = 0; i < 64; i++) {
        char c = pubkey[i];
        if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
            send_error_response(400, "invalid_pubkey", "Invalid pubkey format", "Pubkey must contain only hex characters");
            log_request("GET", "/list", "none", 400);
            return;
        }
    }
    
    // Get query parameters for since/until filtering
    const char* query_string = getenv("QUERY_STRING");
    long since_timestamp = 0;
    long until_timestamp = 0;
    
    if (query_string) {
        fprintf(stderr, "DEBUG: Query string: %s\r\n", query_string);
        
        // Parse since parameter
        const char* since_param = strstr(query_string, "since=");
        if (since_param) {
            since_timestamp = atol(since_param + 6);
            fprintf(stderr, "DEBUG: Since timestamp: %ld\r\n", since_timestamp);
        }
        
        // Parse until parameter  
        const char* until_param = strstr(query_string, "until=");
        if (until_param) {
            until_timestamp = atol(until_param + 6);
            fprintf(stderr, "DEBUG: Until timestamp: %ld\r\n", until_timestamp);
        }
    }
    
    // Check for optional authorization
    const char* auth_header = getenv("HTTP_AUTHORIZATION");
    const char* auth_status = "none";
    
    if (auth_header) {
        fprintf(stderr, "DEBUG: Authorization header provided for list request\r\n");
        int auth_result = authenticate_request_with_rules(auth_header, "list", NULL, NULL, 0);
        if (auth_result != NOSTR_SUCCESS) {
            send_error_response(401, "authentication_failed", "Invalid or expired authentication", 
                              "The provided Nostr event is invalid, expired, or does not authorize this operation");
            log_request("GET", "/list", "failed", 401);
            return;
        }
        auth_status = "authenticated";
    }
    
    // Query database for blobs uploaded by this pubkey
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc) {
        fprintf(stderr, "DEBUG: Database open failed: %s\r\n", sqlite3_errmsg(db));
        send_error_response(500, "database_error", "Failed to access database", "Internal server error");
        log_request("GET", "/list", auth_status, 500);
        return;
    }
    
    // Build SQL query with optional timestamp filtering
    char sql[1024];
    if (since_timestamp > 0 && until_timestamp > 0) {
        snprintf(sql, sizeof(sql), 
                "SELECT sha256, size, type, uploaded_at, filename FROM blobs WHERE uploader_pubkey = ? AND uploaded_at >= ? AND uploaded_at <= ? ORDER BY uploaded_at DESC");
    } else if (since_timestamp > 0) {
        snprintf(sql, sizeof(sql), 
                "SELECT sha256, size, type, uploaded_at, filename FROM blobs WHERE uploader_pubkey = ? AND uploaded_at >= ? ORDER BY uploaded_at DESC");
    } else if (until_timestamp > 0) {
        snprintf(sql, sizeof(sql), 
                "SELECT sha256, size, type, uploaded_at, filename FROM blobs WHERE uploader_pubkey = ? AND uploaded_at <= ? ORDER BY uploaded_at DESC");
    } else {
        snprintf(sql, sizeof(sql), 
                "SELECT sha256, size, type, uploaded_at, filename FROM blobs WHERE uploader_pubkey = ? ORDER BY uploaded_at DESC");
    }
    
    fprintf(stderr, "DEBUG: SQL query: %s\r\n", sql);
    
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "DEBUG: SQL prepare failed: %s\r\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        send_error_response(500, "database_error", "Failed to prepare query", "Internal server error");
        log_request("GET", "/list", auth_status, 500);
        return;
    }
    
    // Bind parameters
    sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
    int param_index = 2;
    
    if (since_timestamp > 0) {
        sqlite3_bind_int64(stmt, param_index++, since_timestamp);
    }
    if (until_timestamp > 0) {
        sqlite3_bind_int64(stmt, param_index++, until_timestamp);
    }
    
    // Start JSON response
    printf("Status: 200 OK\r\n");
    printf("Content-Type: application/json\r\n\r\n");
    printf("[\n");
    
    int first_item = 1;
    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        if (!first_item) {
            printf(",\n");
        }
        first_item = 0;
        
        const char* sha256 = (const char*)sqlite3_column_text(stmt, 0);
        long size = sqlite3_column_int64(stmt, 1);
        const char* type = (const char*)sqlite3_column_text(stmt, 2);
        long uploaded_at = sqlite3_column_int64(stmt, 3);
        const char* filename = (const char*)sqlite3_column_text(stmt, 4);
        
        // Determine file extension from MIME type
        const char* extension = "";
        if (strstr(type, "image/jpeg")) {
            extension = ".jpg";
        } else if (strstr(type, "image/webp")) {
            extension = ".webp";
        } else if (strstr(type, "image/png")) {
            extension = ".png";
        } else if (strstr(type, "image/gif")) {
            extension = ".gif";
        } else if (strstr(type, "video/mp4")) {
            extension = ".mp4";
        } else if (strstr(type, "video/webm")) {
            extension = ".webm";
        } else if (strstr(type, "audio/mpeg")) {
            extension = ".mp3";
        } else if (strstr(type, "audio/ogg")) {
            extension = ".ogg";
        } else if (strstr(type, "text/plain")) {
            extension = ".txt";
        } else {
            extension = ".bin";
        }
        
        // Output blob descriptor JSON
        printf("  {\n");
        printf("    \"url\": \"http://localhost:9001/%s%s\",\n", sha256, extension);
        printf("    \"sha256\": \"%s\",\n", sha256);
        printf("    \"size\": %ld,\n", size);
        printf("    \"type\": \"%s\",\n", type);
        printf("    \"uploaded\": %ld", uploaded_at);
        
        // Add optional filename if available
        if (filename && strlen(filename) > 0) {
            printf(",\n    \"filename\": \"%s\"", filename);
        }
        
        printf("\n  }");
    }
    
    printf("\n]\n");
    
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    
    fprintf(stderr, "DEBUG: List request completed successfully\r\n");
    log_request("GET", "/list", auth_status, 200);
}

// Handle DELETE /<sha256> requests
void handle_delete_request(const char* sha256) {
    fprintf(stderr, "DEBUG: handle_delete_request called with sha256=%s\r\n", sha256 ? sha256 : "NULL");
    
    // Log the incoming request
    log_request("DELETE", "/delete", "pending", 0);
    
    // Validate SHA-256 format (64 hex characters)
    if (!sha256 || strlen(sha256) != 64) {
        send_error_response(400, "invalid_hash", "Invalid SHA-256 hash format", "Hash must be 64 hex characters");
        log_request("DELETE", "/delete", "none", 400);
        return;
    }
    
    // Validate hex characters
    for (int i = 0; i < 64; i++) {
        char c = sha256[i];
        if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
            send_error_response(400, "invalid_hash", "Invalid SHA-256 hash format", "Hash must contain only hex characters");
            log_request("DELETE", "/delete", "none", 400);
            return;
        }
    }
    
    // Require authorization for delete operations
    const char* auth_header = getenv("HTTP_AUTHORIZATION");
    if (!auth_header) {
        send_error_response(401, "authorization_required", "Authorization required for delete operations", 
                          "Delete operations require a valid Nostr authorization event");
        log_request("DELETE", "/delete", "missing_auth", 401);
        return;
    }
    
    // Authenticate the request with enhanced rules system
    int auth_result = authenticate_request_with_rules(auth_header, "delete", sha256, NULL, 0);
    if (auth_result != NOSTR_SUCCESS) {
        send_error_response(401, "authentication_failed", "Invalid or expired authentication", 
                          "The provided Nostr event is invalid, expired, or does not authorize this operation");
        log_request("DELETE", "/delete", "failed", 401);
        return;
    }
    
    // Extract pubkey from authorization for ownership check
    char event_json[4096];
    int parse_result = parse_authorization_header(auth_header, event_json, sizeof(event_json));
    if (parse_result != NOSTR_SUCCESS) {
        send_error_response(401, "authentication_failed", "Failed to parse authorization", 
                          "The provided authorization could not be parsed");
        log_request("DELETE", "/delete", "parse_failed", 401);
        return;
    }
    
    cJSON* event = cJSON_Parse(event_json);
    if (!event) {
        send_error_response(401, "authentication_failed", "Invalid JSON in authorization", 
                          "The provided authorization contains invalid JSON");
        log_request("DELETE", "/delete", "invalid_json", 401);
        return;
    }
    
    cJSON* pubkey_json = cJSON_GetObjectItem(event, "pubkey");
    if (!pubkey_json || !cJSON_IsString(pubkey_json)) {
        cJSON_Delete(event);
        send_error_response(401, "authentication_failed", "Missing pubkey in authorization", 
                          "The provided authorization does not contain a valid pubkey");
        log_request("DELETE", "/delete", "missing_pubkey", 401);
        return;
    }
    
    const char* auth_pubkey = cJSON_GetStringValue(pubkey_json);
    fprintf(stderr, "DEBUG-DELETE: Extracted auth_pubkey from DELETE request: '%s' (length: %zu)\r\n",
            auth_pubkey ? auth_pubkey : "NULL", auth_pubkey ? strlen(auth_pubkey) : 0);
    cJSON_Delete(event);
    
    // Check if blob exists in database
    sqlite3* db;
    sqlite3_stmt* stmt;
    int rc;
    
    rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READWRITE, NULL);
    if (rc) {
        fprintf(stderr, "DEBUG: Database open failed: %s\r\n", sqlite3_errmsg(db));
        send_error_response(500, "database_error", "Failed to access database", "Internal server error");
        log_request("DELETE", "/delete", "authenticated", 500);
        return;
    }
    
    // Query blob metadata and check ownership
    const char* sql = "SELECT uploader_pubkey, type FROM blobs WHERE sha256 = ?";
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "DEBUG: SQL prepare failed: %s\r\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        send_error_response(500, "database_error", "Failed to prepare query", "Internal server error");
        log_request("DELETE", "/delete", "authenticated", 500);
        return;
    }
    
    sqlite3_bind_text(stmt, 1, sha256, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_ROW) {
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        send_error_response(404, "blob_not_found", "Blob not found", "The specified blob does not exist");
        log_request("DELETE", "/delete", "authenticated", 404);
        return;
    }
    
    // Get blob metadata
    const char* uploader_pubkey = (const char*)sqlite3_column_text(stmt, 0);
    const char* blob_type = (const char*)sqlite3_column_text(stmt, 1);

    fprintf(stderr, "DEBUG-DELETE: Database query results:\r\n");
    fprintf(stderr, "DEBUG-DELETE:   Raw uploader_pubkey from DB: '%s'\r\n", uploader_pubkey ? uploader_pubkey : "NULL");
    fprintf(stderr, "DEBUG-DELETE:   Raw blob_type from DB: '%s'\r\n", blob_type ? blob_type : "NULL");
    
    // Create copies of the strings since they may be invalidated after finalize
    char uploader_pubkey_copy[256] = {0};
    char blob_type_copy[128] = {0};
    
    if (uploader_pubkey) {
        strncpy(uploader_pubkey_copy, uploader_pubkey, sizeof(uploader_pubkey_copy) - 1);
    }
    if (blob_type) {
        strncpy(blob_type_copy, blob_type, sizeof(blob_type_copy) - 1);
    }
    
    sqlite3_finalize(stmt);

    fprintf(stderr, "DEBUG-DELETE: After copying strings:\r\n");
    fprintf(stderr, "DEBUG-DELETE:   uploader_pubkey_copy: '%s' (length: %zu)\r\n",
            uploader_pubkey_copy[0] ? uploader_pubkey_copy : "EMPTY", strlen(uploader_pubkey_copy));
    fprintf(stderr, "DEBUG-DELETE:   blob_type_copy: '%s'\r\n", blob_type_copy[0] ? blob_type_copy : "EMPTY");
    
    // Check ownership - only the uploader can delete
    fprintf(stderr, "DEBUG-DELETE: Ownership verification:\r\n");
    fprintf(stderr, "DEBUG-DELETE:   Comparing uploader_pubkey_copy='%s'\r\n", uploader_pubkey_copy);
    fprintf(stderr, "DEBUG-DELETE:   Against auth_pubkey='%s'\r\n", auth_pubkey ? auth_pubkey : "NULL");
    fprintf(stderr, "DEBUG-DELETE:   uploader_pubkey_copy[0]=%d\r\n", (int)uploader_pubkey_copy[0]);
    fprintf(stderr, "DEBUG-DELETE:   strcmp result would be: %d\r\n",
            uploader_pubkey_copy[0] ? strcmp(uploader_pubkey_copy, auth_pubkey) : -999);

    if (!uploader_pubkey_copy[0] || strcmp(uploader_pubkey_copy, auth_pubkey) != 0) {
        fprintf(stderr, "DEBUG-DELETE: OWNERSHIP CHECK FAILED!\r\n");
        fprintf(stderr, "DEBUG-DELETE:   Reason: %s\r\n",
                !uploader_pubkey_copy[0] ? "uploader_pubkey_copy is empty" : "pubkeys don't match");
        sqlite3_close(db);
        send_error_response(403, "access_denied", "Access denied", "You can only delete blobs that you uploaded");
        log_request("DELETE", "/delete", "ownership_denied", 403);
        return;
    } else {
        fprintf(stderr, "DEBUG-DELETE: OWNERSHIP CHECK PASSED!\r\n");
    }
    
    fprintf(stderr, "DEBUG: Ownership check passed, proceeding with deletion\r\n");
    
    // Delete from database first
    const char* delete_sql = "DELETE FROM blobs WHERE sha256 = ?";
    rc = sqlite3_prepare_v2(db, delete_sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "DEBUG: Delete SQL prepare failed: %s\r\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        send_error_response(500, "database_error", "Failed to prepare delete", "Internal server error");
        log_request("DELETE", "/delete", "authenticated", 500);
        return;
    }
    
    sqlite3_bind_text(stmt, 1, sha256, -1, SQLITE_STATIC);
    
    rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "DEBUG: Database delete failed: %d\r\n", rc);
        send_error_response(500, "database_error", "Failed to delete blob metadata", "Internal server error");
        log_request("DELETE", "/delete", "authenticated", 500);
        return;
    }
    
    fprintf(stderr, "DEBUG: Blob metadata deleted from database\r\n");
    
    // Determine file extension from MIME type and delete physical file
    const char* extension = "";
    if (strstr(blob_type_copy, "image/jpeg")) {
        extension = ".jpg";
    } else if (strstr(blob_type_copy, "image/webp")) {
        extension = ".webp";
    } else if (strstr(blob_type_copy, "image/png")) {
        extension = ".png";
    } else if (strstr(blob_type_copy, "image/gif")) {
        extension = ".gif";
    } else if (strstr(blob_type_copy, "video/mp4")) {
        extension = ".mp4";
    } else if (strstr(blob_type_copy, "video/webm")) {
        extension = ".webm";
    } else if (strstr(blob_type_copy, "audio/mpeg")) {
        extension = ".mp3";
    } else if (strstr(blob_type_copy, "audio/ogg")) {
        extension = ".ogg";
    } else if (strstr(blob_type_copy, "text/plain")) {
        extension = ".txt";
    } else {
        extension = ".bin";
    }
    
    char filepath[MAX_PATH_LEN];
    snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256, extension);
    
    fprintf(stderr, "DEBUG: Attempting to delete file: %s\r\n", filepath);
    
    if (unlink(filepath) != 0) {
        fprintf(stderr, "DEBUG: Failed to delete physical file: %s\r\n", filepath);
        // File deletion failed, but database is already updated
        // Log warning but don't fail the request
        fprintf(stderr, "WARNING: Physical file deletion failed, but metadata was removed\r\n");
    } else {
        fprintf(stderr, "DEBUG: Physical file deleted successfully\r\n");
    }
    
    // Return success response
    printf("Status: 200 OK\r\n");
    printf("Content-Type: application/json\r\n\r\n");
    printf("{\n");
    printf("  \"message\": \"Blob deleted successfully\",\n");
    printf("  \"sha256\": \"%s\"\n", sha256);
    printf("}\n");
    
    fprintf(stderr, "DEBUG: Delete operation completed successfully\r\n");
    log_request("DELETE", "/delete", "authenticated", 200);
}

// Handle PUT /upload requests
void handle_upload_request(void) {
    
    // Log the incoming request
    log_request("PUT", "/upload", "pending", 0);
    
    // Get HTTP headers
    const char* content_type = getenv("CONTENT_TYPE");
    const char* content_length_str = getenv("CONTENT_LENGTH");
    
    fprintf(stderr, "DEBUG: content_type=%s\r\n", content_type ? content_type : "NULL");
    fprintf(stderr, "DEBUG: content_length=%s\r\n", content_length_str ? content_length_str : "NULL");
    
    // Validate required headers
    if (!content_type) {
        send_error_response(400, "missing_header", "Content-Type header required", "The Content-Type header must be specified for file uploads");
        log_request("PUT", "/upload", "none", 400);
        return;
    }
    
    if (!content_length_str) {
        send_error_response(400, "missing_header", "Content-Length header required", "The Content-Length header must be specified for file uploads");
        log_request("PUT", "/upload", "none", 400);
        return;
    }
    
    long content_length = atol(content_length_str);
    if (content_length <= 0 || content_length > 100 * 1024 * 1024) { // 100MB limit
        send_error_response(413, "payload_too_large", "File size must be between 1 byte and 100MB", "Maximum allowed file size is 100MB");
        log_request("PUT", "/upload", "none", 413);
        return;
    }
    
    // Get Authorization header for authentication
    const char* auth_header = getenv("HTTP_AUTHORIZATION");
    fprintf(stderr, "DEBUG: Raw Authorization header: %s\r\n", auth_header ? auth_header : "NULL");
    
    // Store uploader pubkey for metadata (will be extracted during auth if provided)
    const char* uploader_pubkey = NULL;
    if (auth_header) {
        log_request("PUT", "/upload", "auth_provided", 0);
    } else {
        log_request("PUT", "/upload", "anonymous", 0);
    }
    
    // Read file data from stdin
    unsigned char* file_data = malloc(content_length);
    if (!file_data) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Memory allocation failed\n");
        return;
    }
    
    size_t bytes_read = fread(file_data, 1, content_length, stdin);
    if (bytes_read != (size_t)content_length) {
        fprintf(stderr, "DEBUG: Expected %ld bytes, read %zu bytes\r\n", content_length, bytes_read);
        free(file_data);
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Failed to read complete file data\n");
        return;
    }

    // Calculate SHA-256 hash using nostr_core function
    unsigned char hash[32];

    
    // EMERGENCY DEBUG: Write to direct file
    FILE* debug_file = fopen("debug_hash_data.log", "a");
    if (debug_file) {
        fprintf(debug_file, "=== HASH DEBUG SESSION ===\n");
        fprintf(debug_file, "Content length: %ld\n", content_length);
        fprintf(debug_file, "File data to hash: ");
        for (int i = 0; i < content_length; i++) {
            fprintf(debug_file, "%02x", (unsigned char)file_data[i]);
        }
        fprintf(debug_file, "\n");
        fprintf(debug_file, "File data as string: %.*s\n", (int)content_length, file_data);
        fclose(debug_file);
    }
    
    if (nostr_sha256(file_data, content_length, hash) != NOSTR_SUCCESS) {
        free(file_data);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Hash calculation failed\n");
        return;
    }
    
    // Convert hash to hex string
    char sha256_hex[65];
    nostr_bytes_to_hex(hash, 32, sha256_hex);
    fprintf(stderr, "DEBUG-LAAN: Calculated SHA-256: %s\r\n", sha256_hex);
    fflush(stderr);
    
    // EMERGENCY DEBUG: Write calculated hash to direct file
    FILE* debug_file2 = fopen("debug_hash_data.log", "a");
    if (debug_file2) {
        fprintf(debug_file2, "Calculated SHA-256: %s\n", sha256_hex);
        fprintf(debug_file2, "=== END DEBUG SESSION ===\n\n");
        fclose(debug_file2);
    }
    
    // TEMPORARY FIX: Bypass rules system and use simple authentication
    fprintf(stderr, "AUTH: About to perform authentication - auth_header present: %s\r\n", auth_header ? "YES" : "NO");
    int auth_result = NOSTR_SUCCESS;
    if (auth_header) {
        fprintf(stderr, "AUTH: Calling authenticate_request with hash: %s\r\n", sha256_hex);
        auth_result = authenticate_request(auth_header, "upload", sha256_hex);
        fprintf(stderr, "AUTH: authenticate_request returned: %d\r\n", auth_result);
        if (auth_result != NOSTR_SUCCESS) {
            free(file_data);
            
            // Provide specific error messages based on the authentication failure type
            const char* error_type = "authentication_failed";
            const char* message = "Authentication failed";
            const char* details = "The request failed nostr authentication";
            
            switch (auth_result) {
                case NOSTR_ERROR_EVENT_INVALID_CONTENT:
                    error_type = "event_expired";
                    message = "Authentication event expired";
                    details = "The provided nostr event has expired and is no longer valid";
                    break;
                case NOSTR_ERROR_EVENT_INVALID_SIGNATURE:
                    error_type = "invalid_signature";
                    message = "Invalid cryptographic signature";
                    details = "The event signature verification failed";
                    break;
                case NOSTR_ERROR_EVENT_INVALID_PUBKEY:
                    error_type = "invalid_pubkey";
                    message = "Invalid public key";
                    details = "The event contains an invalid or malformed public key";
                    break;
                case NOSTR_ERROR_EVENT_INVALID_ID:
                    error_type = "invalid_event_id";
                    message = "Invalid event ID";
                    details = "The event ID does not match the calculated hash";
                    break;
                case NOSTR_ERROR_INVALID_INPUT:
                    error_type = "invalid_format";
                    message = "Invalid authorization format";
                    details = "The authorization header format is invalid or malformed";
                    break;
                default:
                    error_type = "authentication_failed";
                    message = "Authentication failed";
                    // Use C-style string formatting for error details
                    static char error_details_buffer[256];
                    snprintf(error_details_buffer, sizeof(error_details_buffer),
                            "The request failed nostr authentication (error code: %d - %s)",
                            auth_result, nostr_strerror(auth_result));
                    details = error_details_buffer;
                    break;
            }
            
            send_error_response(401, error_type, message, details);
            log_request("PUT", "/upload", "auth_failed", 401);
            return;
        }
    }
    
    // Extract uploader pubkey from authorization if provided
    if (auth_header) {
        char event_json[4096];
        int parse_result = parse_authorization_header(auth_header, event_json, sizeof(event_json));
        if (parse_result == NOSTR_SUCCESS) {
            cJSON* event = cJSON_Parse(event_json);
            if (event) {
                cJSON* pubkey_json = cJSON_GetObjectItem(event, "pubkey");
                if (pubkey_json && cJSON_IsString(pubkey_json)) {
                    static char pubkey_buffer[256];
                    const char* temp_pubkey = cJSON_GetStringValue(pubkey_json);
                    if (temp_pubkey) {
                        strncpy(pubkey_buffer, temp_pubkey, sizeof(pubkey_buffer)-1);
                        pubkey_buffer[sizeof(pubkey_buffer)-1] = '\0';
                        uploader_pubkey = pubkey_buffer;
                    }
                }
                cJSON_Delete(event);
            }
        }
    }
    
    fprintf(stderr, "DEBUG: Authentication passed, uploader_pubkey: %s\r\n", uploader_pubkey ? uploader_pubkey : "anonymous");
    
    // Determine file extension from Content-Type
    const char* extension = "";
    if (strstr(content_type, "image/jpeg")) {
        extension = ".jpg";
    } else if (strstr(content_type, "image/webp")) {
        extension = ".webp";
    } else if (strstr(content_type, "image/png")) {
        extension = ".png";
    } else if (strstr(content_type, "image/gif")) {
        extension = ".gif";
    } else if (strstr(content_type, "video/mp4")) {
        extension = ".mp4";
    } else if (strstr(content_type, "video/webm")) {
        extension = ".webm";
    } else if (strstr(content_type, "audio/mpeg")) {
        extension = ".mp3";
    } else if (strstr(content_type, "audio/ogg")) {
        extension = ".ogg";
    } else if (strstr(content_type, "text/plain")) {
        extension = ".txt";
    } else {
        // Default to binary extension for unknown types
        extension = ".bin";
    }
    
    // Save file to blobs directory with SHA-256 + extension
    char filepath[MAX_PATH_LEN];
    snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256_hex, extension);
    
    fprintf(stderr, "DEBUG: Saving file to: %s\r\n", filepath);
    
    FILE* outfile = fopen(filepath, "wb");
    if (!outfile) {
        free(file_data);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Failed to create file\n");
        return;
    }
    
    size_t bytes_written = fwrite(file_data, 1, content_length, outfile);
    fclose(outfile);
    
    // Set file permissions to 644 (owner read/write, group/others read) - standard for web files
    if (chmod(filepath, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
        fprintf(stderr, "WARNING: Failed to set file permissions for %s\r\n", filepath);
        // Continue anyway - this is not a fatal error
    } else {
        fprintf(stderr, "DEBUG: File permissions set to 644 for %s\r\n", filepath);
    }
    free(file_data);
    
    if (bytes_written != (size_t)content_length) {
        // Clean up partial file
        unlink(filepath);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Failed to write complete file\n");
        return;
    }
    
    fprintf(stderr, "DEBUG: Successfully saved %zu bytes to %s\r\n", bytes_written, filepath);
    
    // Extract filename from Content-Disposition header if present
    const char* filename = NULL;
    const char* content_disposition = getenv("HTTP_CONTENT_DISPOSITION");
    fprintf(stderr, "DEBUG: Content-Disposition header: %s\r\n", content_disposition ? content_disposition : "NULL");
    
    if (content_disposition) {
        fprintf(stderr, "DEBUG: Looking for filename= in Content-Disposition header\r\n");
        // Look for filename= in Content-Disposition header
        const char* filename_start = strstr(content_disposition, "filename=");
        if (filename_start) {
            fprintf(stderr, "DEBUG: Found filename= at position %ld\r\n", filename_start - content_disposition);
            filename_start += 9; // Skip "filename="
            fprintf(stderr, "DEBUG: Filename value starts with: %.20s\r\n", filename_start);
            
            // Handle quoted filenames
            if (*filename_start == '"') {
                fprintf(stderr, "DEBUG: Processing quoted filename\r\n");
                filename_start++; // Skip opening quote
                // Find closing quote
                const char* filename_end = strchr(filename_start, '"');
                if (filename_end) {
                    // Extract filename between quotes
                    static char filename_buffer[256];
                    size_t filename_len = filename_end - filename_start;
                    fprintf(stderr, "DEBUG: Quoted filename length: %zu\r\n", filename_len);
                    if (filename_len < sizeof(filename_buffer)) {
                        strncpy(filename_buffer, filename_start, filename_len);
                        filename_buffer[filename_len] = '\0';
                        filename = filename_buffer;
                        fprintf(stderr, "DEBUG: Extracted quoted filename: '%s'\r\n", filename);
                    } else {
                        fprintf(stderr, "DEBUG: Quoted filename too long, skipping\r\n");
                    }
                } else {
                    fprintf(stderr, "DEBUG: No closing quote found for filename\r\n");
                }
            } else {
                fprintf(stderr, "DEBUG: Processing unquoted filename\r\n");
                // Unquoted filename - extract until space or end
                const char* filename_end = filename_start;
                while (*filename_end && *filename_end != ' ' && *filename_end != ';') {
                    filename_end++;
                }
                static char filename_buffer[256];
                size_t filename_len = filename_end - filename_start;
                fprintf(stderr, "DEBUG: Unquoted filename length: %zu\r\n", filename_len);
                if (filename_len < sizeof(filename_buffer)) {
                    strncpy(filename_buffer, filename_start, filename_len);
                    filename_buffer[filename_len] = '\0';
                    filename = filename_buffer;
                    fprintf(stderr, "DEBUG: Extracted unquoted filename: '%s'\r\n", filename);
                } else {
                    fprintf(stderr, "DEBUG: Unquoted filename too long, skipping\r\n");
                }
            }
        } else {
            fprintf(stderr, "DEBUG: No filename= found in Content-Disposition header\r\n");
        }
    } else {
        fprintf(stderr, "DEBUG: No Content-Disposition header provided\r\n");
    }
    
    fprintf(stderr, "DEBUG: Final filename after extraction: %s\r\n", filename ? filename : "NULL");
    
    // Store blob metadata in database
    time_t uploaded_time = time(NULL);
    if (!insert_blob_metadata(sha256_hex, content_length, content_type, uploaded_time, uploader_pubkey, filename)) {
        // Database insertion failed - clean up the physical file to maintain consistency
        fprintf(stderr, "DEBUG: Database insertion failed, removing physical file\r\n");
        unlink(filepath);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: text/plain\r\n\r\n");
        printf("Failed to store blob metadata\n");
        return;
    }
    
    fprintf(stderr, "DEBUG: Blob metadata successfully stored in database\r\n");
    
    // Return success response with blob descriptor
    printf("Status: 200 OK\r\n");
    printf("Content-Type: application/json\r\n\r\n");
    printf("{\n");
    printf("  \"sha256\": \"%s\",\n", sha256_hex);
    printf("  \"size\": %ld,\n", content_length);
    printf("  \"type\": \"%s\",\n", content_type);
    printf("  \"uploaded\": %ld,\n", uploaded_time);
    printf("  \"url\": \"http://localhost:9001/%s%s\"\n", sha256_hex, extension);
    printf("}\n");
    
    fprintf(stderr, "DEBUG: Upload completed successfully with database storage\r\n");
}

int main(void) {
    fprintf(stderr, "STARTUP: FastCGI application starting up\r\n");
    fflush(stderr);
    
    // CRITICAL: Initialize nostr crypto system for cryptographic operations
    fprintf(stderr, "STARTUP: Initializing nostr crypto system...\r\n");
    if (nostr_crypto_init() != 0) {
        fprintf(stderr, "FATAL ERROR: Failed to initialize nostr crypto system\r\n");
        return 1;
    }
    fprintf(stderr, "STARTUP: nostr crypto system initialized successfully\r\n");
    fflush(stderr);
    while (FCGI_Accept() >= 0) {
        // DEBUG: Log every request received
        
        const char* request_method = getenv("REQUEST_METHOD");
        const char* request_uri = getenv("REQUEST_URI");
        
        
        if (!request_method || !request_uri) {
            printf("Status: 400 Bad Request\r\n");
            printf("Content-Type: text/plain\r\n\r\n");
            printf("Invalid request\n");
            continue;
        }
        
        // Handle HEAD requests for blob metadata
        if (strcmp(request_method, "HEAD") == 0) {
            const char* sha256 = extract_sha256_from_uri(request_uri);
            fprintf(stderr, "DEBUG: Extracted SHA256=%s\r\n", sha256 ? sha256 : "NULL");
            if (sha256) {
                handle_head_request(sha256);
                log_request("HEAD", request_uri, "none", 200); // Assuming success - could be enhanced to track actual status
            } else {
                printf("Status: 400 Bad Request\r\n");
                printf("Content-Type: text/plain\r\n\r\n");
                printf("Invalid SHA-256 hash in URI\n");
                log_request("HEAD", request_uri, "none", 400);
            }
        } else if (strcmp(request_method, "PUT") == 0 && strcmp(request_uri, "/upload") == 0) {
            // Handle PUT /upload requests with authentication
            handle_upload_request();
        } else if (strcmp(request_method, "GET") == 0 && strncmp(request_uri, "/list/", 6) == 0) {
            // Handle GET /list/<pubkey> requests
            const char* pubkey = request_uri + 6; // Skip "/list/"
            
            // Extract pubkey from URI (remove query string if present)
            static char pubkey_buffer[65];
            const char* query_start = strchr(pubkey, '?');
            size_t pubkey_len;
            
            if (query_start) {
                pubkey_len = query_start - pubkey;
            } else {
                pubkey_len = strlen(pubkey);
            }
            
            if (pubkey_len == 64) { // Valid pubkey length
                strncpy(pubkey_buffer, pubkey, 64);
                pubkey_buffer[64] = '\0';
                handle_list_request(pubkey_buffer);
            } else {
                send_error_response(400, "invalid_pubkey", "Invalid pubkey format", "Pubkey must be 64 hex characters");
                log_request("GET", request_uri, "none", 400);
            }
        } else if (strcmp(request_method, "DELETE") == 0) {
            // Handle DELETE /<sha256> requests
            const char* sha256 = extract_sha256_from_uri(request_uri);
            fprintf(stderr, "DEBUG: DELETE request - extracted SHA256=%s\r\n", sha256 ? sha256 : "NULL");
            if (sha256) {
                handle_delete_request(sha256);
            } else {
                send_error_response(400, "invalid_hash", "Invalid SHA-256 hash in URI", "URI must contain a valid 64-character hex hash");
                log_request("DELETE", request_uri, "none", 400);
            }
        } else {
            // Other methods not implemented yet
            printf("Status: 501 Not Implemented\r\n");
            printf("Content-Type: text/plain\r\n\r\n");
            printf("Method %s not implemented\n", request_method);
            log_request(request_method, request_uri, "none", 501);
        }
    }
    
    return 0;
}
