/*
 * NOSTR Core Library
 * 
 * A C library for NOSTR protocol implementation
 * Self-contained crypto implementation (no external crypto dependencies)
 * 
 * Features:
 * - BIP39 mnemonic generation and validation
 * - BIP32 hierarchical deterministic key derivation (NIP-06 compliant)
 * - NOSTR key pair generation and management
 * - Event creation, signing, and serialization
 * - Relay communication (websocket-based)
 * - Identity management and persistence
 */

#ifndef NOSTR_CORE_H
#define NOSTR_CORE_H

#include <stddef.h>
#include <stdint.h>
#include <time.h>

// Forward declare cJSON to avoid requiring cJSON.h in public header
typedef struct cJSON cJSON;

// Return codes
#define NOSTR_SUCCESS 0
#define NOSTR_ERROR_INVALID_INPUT -1
#define NOSTR_ERROR_CRYPTO_FAILED -2
#define NOSTR_ERROR_MEMORY_FAILED -3
#define NOSTR_ERROR_IO_FAILED -4
#define NOSTR_ERROR_NETWORK_FAILED -5
#define NOSTR_ERROR_NIP04_INVALID_FORMAT -10
#define NOSTR_ERROR_NIP04_DECRYPT_FAILED -11
#define NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL -12
#define NOSTR_ERROR_NIP44_INVALID_FORMAT -13
#define NOSTR_ERROR_NIP44_DECRYPT_FAILED -14
#define NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL -15

// Debug control - uncomment to enable debug output
// #define NOSTR_DEBUG_ENABLED

// Constants
#define NOSTR_PRIVATE_KEY_SIZE 32
#define NOSTR_PUBLIC_KEY_SIZE 32
#define NOSTR_HEX_KEY_SIZE 65  // 64 + null terminator
#define NOSTR_BECH32_KEY_SIZE 100
#define NOSTR_MAX_CONTENT_SIZE 2048
#define NOSTR_MAX_URL_SIZE 256

// NIP-04 Constants
#define NOSTR_NIP04_MAX_PLAINTEXT_SIZE 16777216    // 16MB
#define NOSTR_NIP04_MAX_ENCRYPTED_SIZE 22369621    // ~21.3MB (accounts for base64 overhead + IV)

// Input type detection
typedef enum {
    NOSTR_INPUT_UNKNOWN = 0,
    NOSTR_INPUT_MNEMONIC,
    NOSTR_INPUT_NSEC_HEX,
    NOSTR_INPUT_NSEC_BECH32
} nostr_input_type_t;

// Relay permissions
typedef enum {
    NOSTR_RELAY_READ_WRITE = 0,
    NOSTR_RELAY_READ_ONLY,
    NOSTR_RELAY_WRITE_ONLY
} nostr_relay_permission_t;


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//       LIBRARY MAINTENANCE - KEEP THE SHELVES NICE AND ORGANIZED.
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
 * Initialize the NOSTR core library (must be called before using other functions)
 * 
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_init(void);

/**
 * Cleanup the NOSTR core library (call when done)
 */
void nostr_cleanup(void);

/**
 * Get human-readable error message for error code
 * 
 * @param error_code Error code from other functions
 * @return Human-readable error string
 */
const char* nostr_strerror(int error_code);



////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//                GENERAL NOSTR UTILITIES
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Convert bytes to hexadecimal string
 * 
 * @param bytes Input bytes
 * @param len Number of bytes
 * @param hex Output hex string (must be at least len*2+1 bytes)
 */
void nostr_bytes_to_hex(const unsigned char* bytes, size_t len, char* hex);

/**
 * Convert hexadecimal string to bytes
 * 
 * @param hex Input hex string
 * @param bytes Output bytes buffer
 * @param len Expected number of bytes
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_hex_to_bytes(const char* hex, unsigned char* bytes, size_t len);

/**
 * Generate public key from private key
 * 
 * @param private_key Input private key (32 bytes)
 * @param public_key Output public key (32 bytes, x-only)
 * @return 0 on success, non-zero on failure
 */
int nostr_ec_public_key_from_private_key(const unsigned char* private_key, unsigned char* public_key);

/**
 * Sign a hash using BIP-340 Schnorr signatures (NOSTR standard)
 * 
 * @param private_key Input private key (32 bytes)
 * @param hash Input hash to sign (32 bytes)
 * @param signature Output signature (64 bytes)
 * @return 0 on success, non-zero on failure
 */
int nostr_schnorr_sign(const unsigned char* private_key, const unsigned char* hash, unsigned char* signature);




////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//                NIP-01: BASIC PROTOCOL FLOW
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Create and sign a NOSTR event
 * 
 * @param kind Event kind (0=profile, 1=text, 3=contacts, 10002=relays, etc.)
 * @param content Event content string
 * @param tags cJSON array of tags (NULL for empty tags)
 * @param private_key Private key for signing (32 bytes)
 * @param timestamp Event timestamp (0 for current time)
 * @return cJSON event object (caller must free), NULL on failure
 */
cJSON* nostr_create_and_sign_event(int kind, const char* content, cJSON* tags, const unsigned char* private_key, time_t timestamp);




////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//                NIP-04: ENCRYPTED DIRECT MESSAGES
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Encrypt a message using NIP-04 (ECDH + AES-CBC + Base64)
 * 
 * @param sender_private_key Sender's 32-byte private key
 * @param recipient_public_key Recipient's 32-byte public key (x-only)
 * @param plaintext Message to encrypt
 * @param output Buffer for encrypted result (recommend NOSTR_NIP04_MAX_ENCRYPTED_SIZE)
 * @param output_size Size of output buffer
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_nip04_encrypt(const unsigned char* sender_private_key,
                       const unsigned char* recipient_public_key, 
                       const char* plaintext,
                       char* output,
                       size_t output_size);

/**
 * Decrypt a NIP-04 encrypted message
 * 
 * @param recipient_private_key Recipient's 32-byte private key
 * @param sender_public_key Sender's 32-byte public key (x-only)
 * @param encrypted_data Encrypted message in format "ciphertext?iv=iv"
 * @param output Buffer for decrypted plaintext (recommend NOSTR_NIP04_MAX_PLAINTEXT_SIZE)
 * @param output_size Size of output buffer
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_nip04_decrypt(const unsigned char* recipient_private_key,
                       const unsigned char* sender_public_key,
                       const char* encrypted_data,
                       char* output,
                       size_t output_size);




////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//                NIP-44: VERSIONED ENCRYPTED DIRECT MESSAGES
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Encrypt a message using NIP-44 v2 (ECDH + ChaCha20 + HMAC)
 * 
 * @param sender_private_key Sender's 32-byte private key
 * @param recipient_public_key Recipient's 32-byte public key (x-only)
 * @param plaintext Message to encrypt
 * @param output Buffer for encrypted result (recommend NOSTR_NIP44_MAX_PLAINTEXT_SIZE * 2)
 * @param output_size Size of output buffer
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_nip44_encrypt(const unsigned char* sender_private_key,
                       const unsigned char* recipient_public_key,
                       const char* plaintext,
                       char* output,
                       size_t output_size);

/**
 * Decrypt a NIP-44 encrypted message
 * 
 * @param recipient_private_key Recipient's 32-byte private key
 * @param sender_public_key Sender's 32-byte public key (x-only)
 * @param encrypted_data Base64-encoded encrypted message
 * @param output Buffer for decrypted plaintext
 * @param output_size Size of output buffer
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_nip44_decrypt(const unsigned char* recipient_private_key,
                       const unsigned char* sender_public_key,
                       const char* encrypted_data,
                       char* output,
                       size_t output_size);




////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//                NIP-06: KEY DERIVATION FROM MNEMONIC
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Generate a random NOSTR keypair using cryptographically secure entropy
 * 
 * @param private_key Output buffer for private key (32 bytes)
 * @param public_key Output buffer for public key (32 bytes, x-only)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_generate_keypair(unsigned char* private_key, unsigned char* public_key);


/**
 * Generate a BIP39 mnemonic phrase and derive NOSTR keys
 * 
 * @param mnemonic Output buffer for mnemonic (at least 256 bytes recommended)
 * @param mnemonic_size Size of mnemonic buffer
 * @param account Account number for key derivation (default: 0)
 * @param private_key Output buffer for private key (32 bytes)
 * @param public_key Output buffer for public key (32 bytes)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_generate_mnemonic_and_keys(char* mnemonic, size_t mnemonic_size, 
                                    int account, unsigned char* private_key, 
                                    unsigned char* public_key);


/**
 * Derive NOSTR keys from existing BIP39 mnemonic (NIP-06 compliant)
 * 
 * @param mnemonic BIP39 mnemonic phrase
 * @param account Account number for derivation path m/44'/1237'/account'/0/0
 * @param private_key Output buffer for private key (32 bytes)
 * @param public_key Output buffer for public key (32 bytes)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_derive_keys_from_mnemonic(const char* mnemonic, int account,
                                   unsigned char* private_key, unsigned char* public_key);


/**
 * Convert NOSTR key to bech32 format (nsec/npub)
 * 
 * @param key Key data (32 bytes)
 * @param hrp Human readable part ("nsec" or "npub")
 * @param output Output buffer (at least 100 bytes recommended)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_key_to_bech32(const unsigned char* key, const char* hrp, char* output);


/**
 * Detect the type of input string (mnemonic, hex nsec, bech32 nsec)
 * 
 * @param input Input string to analyze
 * @return Input type enum
 */
nostr_input_type_t nostr_detect_input_type(const char* input);


/**
 * Validate and decode an nsec (hex or bech32) to private key
 * 
 * @param input Input nsec string
 * @param private_key Output buffer for private key (32 bytes)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_decode_nsec(const char* input, unsigned char* private_key);

/**
 * Validate and decode an npub (hex or bech32) to private key
 * 
 * @param input Input nsec string
 * @param private_key Output buffer for private key (32 bytes)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_decode_npub(const char* input, unsigned char* private_key);


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//                NIP-13: PROOF OF WORK
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Add NIP-13 Proof of Work to an existing event
 * 
 * @param event cJSON event object to add PoW to
 * @param private_key Private key for re-signing the event during mining
 * @param target_difficulty Target number of leading zero bits (default: 2 if 0)
 * @param progress_callback Optional callback for progress updates (nonce, difficulty, user_data)
 * @param user_data User data passed to progress callback
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_add_proof_of_work(cJSON* event, const unsigned char* private_key, 
                           int target_difficulty,
                           void (*progress_callback)(int current_difficulty, uint64_t nonce, void* user_data),
                           void* user_data);





////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//          RELAYS - SYNCHRONOUS MULTI-RELAY QUERIES AND PUBLISHING
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/**
 * Query a relay for a specific event
 * 
 * @param relay_url Relay WebSocket URL (ws:// or wss://)
 * @param pubkey_hex Author's public key in hex format
 * @param kind Event kind to search for
 * @return cJSON event object (caller must free), NULL if not found/error
 */
cJSON* nostr_query_relay_for_event(const char* relay_url, const char* pubkey_hex, int kind);


// Query mode enum
typedef enum {
    RELAY_QUERY_FIRST_RESULT,    // Return as soon as first event is found
    RELAY_QUERY_MOST_RECENT,     // Wait for all relays, return most recent event
    RELAY_QUERY_ALL_RESULTS      // Wait for all relays, return all unique events
} relay_query_mode_t;

// Progress callback type for relay queries
typedef void (*relay_progress_callback_t)(
    const char* relay_url,      // Which relay is reporting (NULL for summary)
    const char* status,         // Status: "connecting", "subscribed", "event_found", "eose", "complete", "timeout", "error", "first_result", "all_complete"
    const char* event_id,       // Event ID when applicable (NULL otherwise)
    int events_received,        // Number of events from this relay
    int total_relays,          // Total number of relays
    int completed_relays,      // Number of relays finished
    void* user_data           // User data pointer
);

/**
 * Query multiple relays synchronously with progress callbacks
 * 
 * @param relay_urls Array of relay WebSocket URLs
 * @param relay_count Number of relays in array
 * @param filter cJSON filter object for query
 * @param mode Query mode (FIRST_RESULT, MOST_RECENT, or ALL_RESULTS)
 * @param result_count OUTPUT: number of events returned
 * @param relay_timeout_seconds Timeout per relay in seconds (default: 2 if <= 0)
 * @param callback Progress callback function (can be NULL)
 * @param user_data User data passed to callback
 * @return Array of cJSON events (caller must free each event and array), NULL on failure
 */
cJSON** synchronous_query_relays_with_progress(
    const char** relay_urls,
    int relay_count,
    cJSON* filter,
    relay_query_mode_t mode,
    int* result_count,
    int relay_timeout_seconds,
    relay_progress_callback_t callback,
    void* user_data
);

// Publish result enum
typedef enum {
    PUBLISH_SUCCESS,     // Event accepted by relay (received OK with true)
    PUBLISH_REJECTED,    // Event rejected by relay (received OK with false)
    PUBLISH_TIMEOUT,     // No response from relay within timeout
    PUBLISH_ERROR        // Connection error or other failure
} publish_result_t;

// Progress callback type for publishing
typedef void (*publish_progress_callback_t)(
    const char* relay_url,      // Which relay is reporting
    const char* status,         // Status: "connecting", "publishing", "accepted", "rejected", "timeout", "error"
    const char* message,        // OK message from relay (for rejected events)
    int successful_publishes,   // Count of successful publishes so far
    int total_relays,          // Total number of relays
    int completed_relays,      // Number of relays finished
    void* user_data           // User data pointer
);

/**
 * Publish event to multiple relays synchronously with progress callbacks
 * 
 * @param relay_urls Array of relay WebSocket URLs
 * @param relay_count Number of relays in array
 * @param event cJSON event object to publish
 * @param success_count OUTPUT: number of successful publishes
 * @param relay_timeout_seconds Timeout per relay in seconds (default: 5 if <= 0)
 * @param callback Progress callback function (can be NULL)
 * @param user_data User data passed to callback
 * @return Array of publish_result_t (caller must free), NULL on failure
 */
publish_result_t* synchronous_publish_event_with_progress(
    const char** relay_urls,
    int relay_count,
    cJSON* event,
    int* success_count,
    int relay_timeout_seconds,
    publish_progress_callback_t callback,
    void* user_data
);





////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//          RELAYS - ASYNCHRONOUS RELAY POOLS
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// Forward declarations for relay pool types
typedef struct nostr_relay_pool nostr_relay_pool_t;
typedef struct nostr_pool_subscription nostr_pool_subscription_t;

// Pool connection status
typedef enum {
    NOSTR_POOL_RELAY_DISCONNECTED = 0,
    NOSTR_POOL_RELAY_CONNECTING = 1,
    NOSTR_POOL_RELAY_CONNECTED = 2,
    NOSTR_POOL_RELAY_ERROR = -1
} nostr_pool_relay_status_t;

// Relay statistics structure
typedef struct {
    // Event counters  
    int events_received;
    int events_published;
    int events_published_ok;
    int events_published_failed;
    
    // Connection stats
    int connection_attempts;
    int connection_failures;
    time_t connection_uptime_start;
    time_t last_event_time;
    
    // Latency measurements (milliseconds)
    // NOTE: ping_latency_* values will be 0.0/-1.0 until PONG response handling is fixed
    double ping_latency_current;
    double ping_latency_avg;
    double ping_latency_min;
    double ping_latency_max;
    double publish_latency_avg;    // EVENT->OK response time
    double query_latency_avg;      // REQ->first EVENT response time
    double query_latency_min;      // Min query latency
    double query_latency_max;      // Max query latency
    
    // Sample counts for averaging
    int ping_samples;
    int publish_samples;
    int query_samples;
} nostr_relay_stats_t;

/**
 * Create a new relay pool for managing multiple relay connections
 * 
 * @return New relay pool instance (caller must destroy), NULL on failure
 */
nostr_relay_pool_t* nostr_relay_pool_create(void);

/**
 * Add a relay to the pool
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay WebSocket URL (ws:// or wss://)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_relay_pool_add_relay(nostr_relay_pool_t* pool, const char* relay_url);

/**
 * Remove a relay from the pool
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to remove
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_relay_pool_remove_relay(nostr_relay_pool_t* pool, const char* relay_url);

/**
 * Destroy relay pool and cleanup all connections
 * 
 * @param pool Relay pool instance to destroy
 */
void nostr_relay_pool_destroy(nostr_relay_pool_t* pool);

/**
 * Subscribe to events from multiple relays with event deduplication
 * 
 * @param pool Relay pool instance
 * @param relay_urls Array of relay URLs to subscribe to
 * @param relay_count Number of relays in array
 * @param filter cJSON filter object for subscription
 * @param on_event Callback for received events (event, relay_url, user_data)
 * @param on_eose Callback when all relays have sent EOSE (user_data)
 * @param user_data User data passed to callbacks
 * @return Subscription handle (caller must close), NULL on failure
 */
nostr_pool_subscription_t* nostr_relay_pool_subscribe(
    nostr_relay_pool_t* pool,
    const char** relay_urls, 
    int relay_count,
    cJSON* filter,
    void (*on_event)(cJSON* event, const char* relay_url, void* user_data),
    void (*on_eose)(void* user_data),
    void* user_data
);

/**
 * Close a pool subscription
 * 
 * @param subscription Subscription to close
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_pool_subscription_close(nostr_pool_subscription_t* subscription);

/**
 * Query multiple relays synchronously and return all matching events
 * 
 * @param pool Relay pool instance
 * @param relay_urls Array of relay URLs to query
 * @param relay_count Number of relays in array
 * @param filter cJSON filter object for query
 * @param event_count Output: number of events returned
 * @param timeout_ms Timeout in milliseconds
 * @return Array of cJSON events (caller must free), NULL on failure/timeout
 */
cJSON** nostr_relay_pool_query_sync(
    nostr_relay_pool_t* pool,
    const char** relay_urls,
    int relay_count, 
    cJSON* filter,
    int* event_count,
    int timeout_ms
);

/**
 * Get a single event from multiple relays (returns the most recent one)
 * 
 * @param pool Relay pool instance
 * @param relay_urls Array of relay URLs to query
 * @param relay_count Number of relays in array
 * @param filter cJSON filter object for query
 * @param timeout_ms Timeout in milliseconds
 * @return cJSON event (caller must free), NULL if not found/timeout
 */
cJSON* nostr_relay_pool_get_event(
    nostr_relay_pool_t* pool,
    const char** relay_urls,
    int relay_count,
    cJSON* filter,
    int timeout_ms
);

/**
 * Publish an event to multiple relays
 * 
 * @param pool Relay pool instance
 * @param relay_urls Array of relay URLs to publish to
 * @param relay_count Number of relays in array
 * @param event cJSON event to publish
 * @return Number of successful publishes, negative on error
 */
int nostr_relay_pool_publish(
    nostr_relay_pool_t* pool,
    const char** relay_urls,
    int relay_count,
    cJSON* event
);

/**
 * Get connection status for a relay in the pool
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to check
 * @return Connection status enum
 */
nostr_pool_relay_status_t nostr_relay_pool_get_relay_status(
    nostr_relay_pool_t* pool, 
    const char* relay_url
);

/**
 * Get list of all relays in pool with their status
 * 
 * @param pool Relay pool instance
 * @param relay_urls Output: array of relay URL strings (caller must free)
 * @param statuses Output: array of status values (caller must free)
 * @return Number of relays, negative on error
 */
int nostr_relay_pool_list_relays(
    nostr_relay_pool_t* pool,
    char*** relay_urls,
    nostr_pool_relay_status_t** statuses
);

/**
 * Run continuous event processing for active subscriptions (blocking)
 * Processes incoming events and calls subscription callbacks until timeout or stopped
 * 
 * @param pool Relay pool instance
 * @param timeout_ms Timeout in milliseconds (0 = no timeout, runs indefinitely)
 * @return Total number of events processed, negative on error
 */
int nostr_relay_pool_run(nostr_relay_pool_t* pool, int timeout_ms);

/**
 * Process events for active subscriptions (non-blocking, single pass)
 * Processes available events and returns immediately
 * 
 * @param pool Relay pool instance
 * @param timeout_ms Maximum time to spend processing in milliseconds
 * @return Number of events processed in this call, negative on error
 */
int nostr_relay_pool_poll(nostr_relay_pool_t* pool, int timeout_ms);

// =============================================================================
// RELAY POOL STATISTICS AND LATENCY
// =============================================================================

/**
 * Get statistics for a specific relay in the pool
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to get statistics for
 * @return Pointer to statistics structure (owned by pool), NULL if relay not found
 */
const nostr_relay_stats_t* nostr_relay_pool_get_relay_stats(
    nostr_relay_pool_t* pool, 
    const char* relay_url
);

/**
 * Reset statistics for a specific relay
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to reset statistics for
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_relay_pool_reset_relay_stats(
    nostr_relay_pool_t* pool, 
    const char* relay_url
);

/**
 * Get current ping latency for a relay (most recent ping result)
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to check
 * @return Ping latency in milliseconds, -1.0 if no ping data available
 */
double nostr_relay_pool_get_relay_ping_latency(
    nostr_relay_pool_t* pool, 
    const char* relay_url
);

/**
 * Get average query latency for a relay (REQ->first EVENT response time)
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to check
 * @return Average query latency in milliseconds, -1.0 if no data available
 */
double nostr_relay_pool_get_relay_query_latency(
    nostr_relay_pool_t* pool, 
    const char* relay_url
);

/**
 * Manually trigger ping measurement for a relay (asynchronous)
 * 
 * NOTE: PING frames are sent correctly, but PONG response handling needs debugging.
 * Currently times out waiting for PONG responses. Future fix needed.
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to ping
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_relay_pool_ping_relay(
    nostr_relay_pool_t* pool, 
    const char* relay_url
);

/**
 * Manually trigger ping measurement for a relay and wait for response (synchronous)
 * 
 * NOTE: PING frames are sent correctly, but PONG response handling needs debugging.
 * Currently times out waiting for PONG responses. Future fix needed.
 * 
 * @param pool Relay pool instance
 * @param relay_url Relay URL to ping
 * @param timeout_seconds Timeout in seconds (0 for default 5 seconds)
 * @return NOSTR_SUCCESS on success, error code on failure
 */
int nostr_relay_pool_ping_relay_sync(
    nostr_relay_pool_t* pool, 
    const char* relay_url, 
    int timeout_seconds
);

#endif // NOSTR_CORE_H
