/*
 * Relay Pool Test Program
 *
 * Tests the nostr_relay_pool functionality with persistent connections
 * and subscriptions. Prints events as they arrive and shows connection status.
 *
 * Usage: ./pool_test
 * Press Ctrl+C to exit
 */

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

// Global variables for signal handling
volatile sig_atomic_t running = 1;
time_t last_status_time = 0;

// Signal handler for clean shutdown
void signal_handler(int signum) {
    (void)signum; // Suppress unused parameter warning
    printf("\n🛑 Received signal, shutting down...\n");
    running = 0;
}

// Event callback - called when an event is received
void on_event(cJSON* event, const char* relay_url, void* user_data) {
    (void)user_data; // Suppress unused parameter warning

    // Extract basic event information
    cJSON* id = cJSON_GetObjectItem(event, "id");
    cJSON* pubkey = cJSON_GetObjectItem(event, "pubkey");
    cJSON* created_at = cJSON_GetObjectItem(event, "created_at");
    cJSON* kind = cJSON_GetObjectItem(event, "kind");
    cJSON* content = cJSON_GetObjectItem(event, "content");

    printf("\n📨 EVENT from %s\n", relay_url);
    printf("├── ID: %.12s...\n", id && cJSON_IsString(id) ? cJSON_GetStringValue(id) : "unknown");
    printf("├── Pubkey: %.12s...\n", pubkey && cJSON_IsString(pubkey) ? cJSON_GetStringValue(pubkey) : "unknown");
    printf("├── Kind: %d\n", kind && cJSON_IsNumber(kind) ? (int)cJSON_GetNumberValue(kind) : -1);
    printf("├── Created: %lld\n", created_at && cJSON_IsNumber(created_at) ? (long long)cJSON_GetNumberValue(created_at) : 0);

    // Truncate content if too long
    if (content && cJSON_IsString(content)) {
        const char* content_str = cJSON_GetStringValue(content);
        size_t content_len = strlen(content_str);
        if (content_len > 100) {
            printf("└── Content: %.97s...\n", content_str);
        } else {
            printf("└── Content: %s\n", content_str);
        }
    } else {
        printf("└── Content: (empty)\n");
    }
    fflush(stdout);
}

// EOSE callback - called when End of Stored Events is received
void on_eose(cJSON** events, int event_count, void* user_data) {
    (void)user_data; // Suppress unused parameter warning
    printf("📋 EOSE received - %d events collected\n", event_count);

    // Log collected events if any
    for (int i = 0; i < event_count; i++) {
        cJSON* id = cJSON_GetObjectItem(events[i], "id");
        if (id && cJSON_IsString(id)) {
            printf("  Event %d: %.12s...\n", i + 1, cJSON_GetStringValue(id));
        }
    }
    fflush(stdout);
}

// Print connection status for all relays
void print_relay_status(nostr_relay_pool_t* pool) {
    char** relay_urls = NULL;
    nostr_pool_relay_status_t* statuses = NULL;
    int relay_count = nostr_relay_pool_list_relays(pool, &relay_urls, &statuses);

    if (relay_count <= 0) {
        printf("❌ No relays in pool\n");
        return;
    }

    printf("\n📊 RELAY STATUS (%d relays):\n", relay_count);
    for (int i = 0; i < relay_count; i++) {
        const char* status_str;
        switch (statuses[i]) {
            case NOSTR_POOL_RELAY_CONNECTED:
                status_str = "🟢 CONNECTED";
                break;
            case NOSTR_POOL_RELAY_CONNECTING:
                status_str = "🟡 CONNECTING";
                break;
            case NOSTR_POOL_RELAY_DISCONNECTED:
                status_str = "⚪ DISCONNECTED";
                break;
            case NOSTR_POOL_RELAY_ERROR:
                status_str = "🔴 ERROR";
                break;
            default:
                status_str = "❓ UNKNOWN";
                break;
        }

        printf("├── %s: %s\n", relay_urls[i], status_str);

        // Show additional stats if available
        const nostr_relay_stats_t* stats = nostr_relay_pool_get_relay_stats(pool, relay_urls[i]);
        if (stats) {
            printf("│   ├── Events received: %d\n", stats->events_received);
            printf("│   ├── Connection attempts: %d\n", stats->connection_attempts);
            printf("│   └── Connection failures: %d\n", stats->connection_failures);
        }

        free(relay_urls[i]);
    }
    printf("\n");
    free(relay_urls);
    free(statuses);
    fflush(stdout);
}

int main() {
    printf("🔗 NOSTR Relay Pool Test\n");
    printf("========================\n");
    printf("Testing persistent relay connections with subscriptions.\n");
    printf("Press Ctrl+C to exit.\n\n");

    // Initialize NOSTR library
    if (nostr_init() != NOSTR_SUCCESS) {
        fprintf(stderr, "❌ Failed to initialize NOSTR library\n");
        return 1;
    }

    // Setup signal handler for clean shutdown
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    // Create relay pool with default configuration
    nostr_pool_reconnect_config_t* config = nostr_pool_reconnect_config_default();
    nostr_relay_pool_t* pool = nostr_relay_pool_create(config);
    if (!pool) {
        fprintf(stderr, "❌ Failed to create relay pool\n");
        nostr_cleanup();
        return 1;
    }

    // Add relays to the pool
    const char* relay_urls[] = {
        "wss://nostr.mom",
        "wss://relay.laantungir.net",
        "wss://nos.lol"
    };
    int relay_count = 3;

    printf("📡 Adding %d relays to pool:\n", relay_count);
    for (int i = 0; i < relay_count; i++) {
        printf("├── %s\n", relay_urls[i]);
        if (nostr_relay_pool_add_relay(pool, relay_urls[i]) != NOSTR_SUCCESS) {
            printf("│   ❌ Failed to add relay\n");
        } else {
            printf("│   ✅ Added successfully\n");
        }
    }
    printf("\n");

    // Create filter for subscription (kind 1 events - text notes)
    cJSON* filter = cJSON_CreateObject();
    cJSON* kinds = cJSON_CreateArray();
    cJSON_AddItemToArray(kinds, cJSON_CreateNumber(1));
    cJSON_AddItemToObject(filter, "kinds", kinds);
    cJSON_AddItemToObject(filter, "limit", cJSON_CreateNumber(10)); // Limit to 10 events per relay

    printf("🔍 Creating subscription with filter:\n");
    char* filter_json = cJSON_Print(filter);
    printf("%s\n\n", filter_json);
    free(filter_json);

    // Create subscription with new parameters
    nostr_pool_subscription_t* subscription = nostr_relay_pool_subscribe(
        pool,
        relay_urls,
        relay_count,
        filter,
        on_event,      // Event callback
        on_eose,       // EOSE callback
        NULL,          // User data (not used)
        0,             // close_on_eose (false - keep subscription open)
        1,             // enable_deduplication
        NOSTR_POOL_EOSE_FULL_SET,  // result_mode
        30,            // relay_timeout_seconds
        60             // eose_timeout_seconds
    );

    if (!subscription) {
        fprintf(stderr, "❌ Failed to create subscription\n");
        cJSON_Delete(filter);
        nostr_relay_pool_destroy(pool);
        nostr_cleanup();
        return 1;
    }

    printf("✅ Subscription created successfully\n");
    printf("🎯 Listening for events... (Ctrl+C to exit)\n\n");

    // Record start time for status updates
    last_status_time = time(NULL);

    // Main event loop
    while (running) {
        // Poll for events (100ms timeout)
        int events_processed = nostr_relay_pool_poll(pool, 100);

        // Check if we should print status (every 30 seconds)
        time_t current_time = time(NULL);
        if (current_time - last_status_time >= 30) {
            print_relay_status(pool);
            last_status_time = current_time;
        }

        // Small delay to prevent busy waiting
        if (events_processed == 0) {
            struct timespec ts = {0, 10000000}; // 10ms
            nanosleep(&ts, NULL);
        }
    }

    printf("\n🧹 Cleaning up...\n");

    // Close subscription
    if (subscription) {
        nostr_pool_subscription_close(subscription);
        printf("✅ Subscription closed\n");
    }

    // Destroy pool
    nostr_relay_pool_destroy(pool);
    printf("✅ Relay pool destroyed\n");

    // Cleanup JSON
    cJSON_Delete(filter);

    // Cleanup library
    nostr_cleanup();

    printf("👋 Test completed successfully\n");
    return 0;
}