/*
 * NOSTR Relay Pool Test Program (READ-ONLY)
 * 
 * Tests the relay pool event processing functionality by:
 * - Creating a pool with hardcoded relays
 * - Subscribing to kind 1 events (text notes) from other users
 * - Using the new event processing functions
 * - Displaying raw data output without interpretation
 * 
 * IMPORTANT: This test is READ-ONLY and never publishes events.
 * It only sends REQ (subscription) messages and receives EVENT responses.
 * Any test events seen in output are from other users or previous test runs.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include "../nostr_core/nostr_core.h"
#include "../cjson/cJSON.h"

// Global variables for clean shutdown
static volatile int keep_running = 1;
static nostr_relay_pool_t* g_pool = NULL;
static nostr_pool_subscription_t* g_subscription = NULL;

// Statistics tracking
static int events_received = 0;
static int events_per_relay[3] = {0, 0, 0}; // Track events per relay
static const char* relay_urls[] = {
    "wss://relay.laantungir.net",
    "ws://127.0.0.1:7777",
    "wss://nostr.mom"
};
static const int relay_count = 3;

// Signal handler for clean shutdown
void signal_handler(int sig) {
    (void)sig; // Unused parameter
    printf("\n🛑 Received shutdown signal, cleaning up...\n");
    keep_running = 0;
}

// Event callback - called when events are received
void on_event_received(cJSON* event, const char* relay_url, void* user_data) {
    (void)user_data; // Unused parameter
    
    events_received++;
    
    // Track events per relay
    for (int i = 0; i < relay_count; i++) {
        if (strcmp(relay_url, relay_urls[i]) == 0) {
            events_per_relay[i]++;
            break;
        }
    }
    
    // Print raw event data
    char* event_json = cJSON_Print(event);
    if (event_json) {
        printf("\n📨 EVENT from %s:\n", relay_url);
        printf("Raw JSON: %s\n", event_json);
        printf("---\n");
        free(event_json);
    }
    
    // Also extract and display key fields for readability
    cJSON* id = cJSON_GetObjectItem(event, "id");
    cJSON* pubkey = cJSON_GetObjectItem(event, "pubkey");
    cJSON* created_at = cJSON_GetObjectItem(event, "created_at");
    cJSON* content = cJSON_GetObjectItem(event, "content");
    
    printf("📄 Parsed fields:\n");
    if (id && cJSON_IsString(id)) {
        printf("   ID: %s\n", cJSON_GetStringValue(id));
    }
    if (pubkey && cJSON_IsString(pubkey)) {
        printf("   Author: %s\n", cJSON_GetStringValue(pubkey));
    }
    if (created_at && cJSON_IsNumber(created_at)) {
        time_t timestamp = (time_t)cJSON_GetNumberValue(created_at);
        printf("   Created: %s", ctime(&timestamp));
    }
    if (content && cJSON_IsString(content)) {
        const char* text = cJSON_GetStringValue(content);
        printf("   Content: %.100s%s\n", text, strlen(text) > 100 ? "..." : "");
    }
    printf("===============================\n");
}

// EOSE callback - called when all relays have sent "End of Stored Events"
void on_eose_received(void* user_data) {
    (void)user_data; // Unused parameter
    printf("✅ EOSE: All relays have finished sending stored events\n");
}

// Display relay status
void display_relay_status() {
    char** urls;
    nostr_pool_relay_status_t* statuses;
    
    int count = nostr_relay_pool_list_relays(g_pool, &urls, &statuses);
    if (count > 0) {
        printf("\n🔗 RELAY STATUS:\n");
        for (int i = 0; i < count; i++) {
            const char* status_icon;
            const char* status_text;
            
            switch (statuses[i]) {
                case NOSTR_POOL_RELAY_CONNECTED:
                    status_icon = "🟢";
                    status_text = "Connected";
                    break;
                case NOSTR_POOL_RELAY_CONNECTING:
                    status_icon = "🟡";
                    status_text = "Connecting...";
                    break;
                case NOSTR_POOL_RELAY_DISCONNECTED:
                    status_icon = "🔴";
                    status_text = "Disconnected";
                    break;
                case NOSTR_POOL_RELAY_ERROR:
                    status_icon = "❌";
                    status_text = "Error";
                    break;
                default:
                    status_icon = "❓";
                    status_text = "Unknown";
                    break;
            }
            
            // Get publish and query latency statistics
            double query_latency = nostr_relay_pool_get_relay_query_latency(g_pool, urls[i]);
            const nostr_relay_stats_t* stats = nostr_relay_pool_get_relay_stats(g_pool, urls[i]);
            
            // Get events count from relay statistics (more accurate)
            int relay_events = 0;
            if (stats) {
                relay_events = stats->events_received;
            } else {
                // Fallback to local counter
                for (int j = 0; j < relay_count; j++) {
                    if (strcmp(urls[i], relay_urls[j]) == 0) {
                        relay_events = events_per_relay[j];
                        break;
                    }
                }
            }
            
            // Display status with latency information
            if (query_latency >= 0.0) {
                printf("   %s %-25s %s (query: %.0fms, events: %d)\n", 
                       status_icon, urls[i], status_text, query_latency, relay_events);
            } else {
                printf("   %s %-25s %s (query: ---, events: %d)\n", 
                       status_icon, urls[i], status_text, relay_events);
            }
            
            // Show additional latency statistics if available
            if (stats) {
                if (stats->publish_samples > 0) {
                    printf("      📊 Publish latency: avg=%.0fms (%d samples)\n",
                           stats->publish_latency_avg, stats->publish_samples);
                }
                if (stats->query_samples > 0) {
                    printf("      📊 Query latency: avg=%.0fms (%d samples)\n",
                           stats->query_latency_avg, stats->query_samples);
                }
                if (stats->events_published > 0) {
                    printf("      📤 Published: %d events (%d OK, %d failed)\n",
                           stats->events_published, stats->events_published_ok, 
                           stats->events_published_failed);
                }
            }
            
            free(urls[i]);
        }
        free(urls);
        free(statuses);
        
        printf("📊 Total events received: %d\n", events_received);
    }
}

int main() {
    printf("🚀 NOSTR Relay Pool Test Program\n");
    printf("=================================\n");
    printf("Testing relays:\n");
    for (int i = 0; i < relay_count; i++) {
        printf("  - %s\n", relay_urls[i]);
    }
    printf("\n");
    
    // Set up signal handler for clean shutdown
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    // Initialize NOSTR core library
    printf("🔧 Initializing NOSTR core library...\n");
    if (nostr_init() != NOSTR_SUCCESS) {
        fprintf(stderr, "❌ Failed to initialize NOSTR core library\n");
        return 1;
    }
    
    // Create relay pool
    printf("🏊 Creating relay pool...\n");
    g_pool = nostr_relay_pool_create();
    if (!g_pool) {
        fprintf(stderr, "❌ Failed to create relay pool\n");
        nostr_cleanup();
        return 1;
    }
    
    // Add relays to pool
    printf("➕ Adding relays to pool...\n");
    for (int i = 0; i < relay_count; i++) {
        printf("   Adding: %s\n", relay_urls[i]);
        int result = nostr_relay_pool_add_relay(g_pool, relay_urls[i]);
        if (result != NOSTR_SUCCESS) {
            printf("   ⚠️  Warning: Failed to add relay %s (error: %s)\n", 
                   relay_urls[i], nostr_strerror(result));
        }
    }
    
    // Create filter for kind 1 events (text notes)
    printf("🔍 Creating subscription filter for kind 1 events...\n");
    cJSON* filter = cJSON_CreateObject();
    if (!filter) {
        fprintf(stderr, "❌ Failed to create filter\n");
        nostr_relay_pool_destroy(g_pool);
        nostr_cleanup();
        return 1;
    }
    
    // Add kinds array with kind 1 (text notes)
    cJSON* kinds = cJSON_CreateArray();
    cJSON_AddItemToArray(kinds, cJSON_CreateNumber(1));
    cJSON_AddItemToObject(filter, "kinds", kinds);
    
    // Limit to recent events to avoid flooding
    cJSON_AddNumberToObject(filter, "limit", 1);
    
    // Subscribe to events from all relays
    printf("📡 Subscribing to events from all relays...\n");
    g_subscription = nostr_relay_pool_subscribe(
        g_pool,
        relay_urls,
        relay_count,
        filter,
        on_event_received,
        on_eose_received,
        NULL
    );
    
    if (!g_subscription) {
        fprintf(stderr, "❌ Failed to create subscription\n");
        cJSON_Delete(filter);
        nostr_relay_pool_destroy(g_pool);
        nostr_cleanup();
        return 1;
    }
    
    printf("✅ Subscription created successfully!\n");
    printf("⏱️  Starting event processing...\n");
    printf("   (Press Ctrl+C to stop)\n\n");
    
    // Display initial status
    display_relay_status();
    
    printf("� Starting continuous monitoring...\n\n");
    
    // Run event processing loop
    time_t last_status_update = time(NULL);
    
    while (keep_running) {
        // Process events for 1 second
        int events_processed = nostr_relay_pool_run(g_pool, 1000);
        
        // Display status every 5 seconds
        if (time(NULL) - last_status_update >= 5) {
            display_relay_status();
            last_status_update = time(NULL);
        }
        
        // Small status indicator
        if (events_processed > 0) {
            printf(".");
            fflush(stdout);
        }
    }
    
    printf("\n\n🏁 Test completed!\n");
    
    // Final status display
    display_relay_status();
    
    // Cleanup
    printf("🧹 Cleaning up...\n");
    if (g_subscription) {
        nostr_pool_subscription_close(g_subscription);
    }
    if (g_pool) {
        nostr_relay_pool_destroy(g_pool);
    }
    cJSON_Delete(filter);
    nostr_cleanup();
    
    printf("✅ Test program finished successfully!\n");
    printf("📈 Final stats:\n");
    printf("   Total events: %d\n", events_received);
    for (int i = 0; i < relay_count; i++) {
        printf("   %s: %d events\n", relay_urls[i], events_per_relay[i]);
    }
    
    return 0;
}
