/*
 * NOSTR Core Library - NIP-042: Authentication of clients to relays
 * 
 * Implements client authentication through signed ephemeral events
 */

#ifndef NIP042_H
#define NIP042_H

#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include "../cjson/cJSON.h"
#include "nostr_common.h"

#ifdef __cplusplus
extern "C" {
#endif

// =============================================================================
// NIP-42 CONSTANTS AND DEFINITIONS
// =============================================================================

#define NOSTR_NIP42_AUTH_EVENT_KIND 22242
#define NOSTR_NIP42_DEFAULT_CHALLENGE_LENGTH 32
#define NOSTR_NIP42_DEFAULT_TIME_TOLERANCE 600  // 10 minutes in seconds
#define NOSTR_NIP42_MAX_CHALLENGE_LENGTH 256
#define NOSTR_NIP42_MIN_CHALLENGE_LENGTH 16

// Authentication states for WebSocket client integration
typedef enum {
    NOSTR_AUTH_STATE_NONE = 0,               // No authentication attempted
    NOSTR_AUTH_STATE_CHALLENGE_RECEIVED = 1,  // Challenge received from relay
    NOSTR_AUTH_STATE_AUTHENTICATING = 2,      // AUTH event sent, waiting for OK
    NOSTR_AUTH_STATE_AUTHENTICATED = 3,       // Successfully authenticated
    NOSTR_AUTH_STATE_REJECTED = 4            // Authentication rejected
} nostr_auth_state_t;

// Challenge storage structure
typedef struct {
    char challenge[NOSTR_NIP42_MAX_CHALLENGE_LENGTH];
    time_t received_at;
    int is_valid;
} nostr_auth_challenge_t;

// Authentication context for relay verification
typedef struct {
    char* relay_url;
    char* challenge;
    time_t timestamp;
    int time_tolerance;
    char* pubkey_hex;
} nostr_auth_context_t;

// =============================================================================
// CLIENT-SIDE FUNCTIONS (for nostr clients)
// =============================================================================

/**
 * Create NIP-42 authentication event (kind 22242)
 * @param challenge Challenge string received from relay
 * @param relay_url Relay URL (normalized)
 * @param private_key 32-byte private key for signing
 * @param timestamp Event timestamp (0 for current time)
 * @return cJSON event object or NULL on error
 */
cJSON* nostr_nip42_create_auth_event(const char* challenge, 
                                      const char* relay_url,
                                      const unsigned char* private_key,
                                      time_t timestamp);

/**
 * Create AUTH message JSON for relay communication
 * @param auth_event Authentication event (kind 22242)
 * @return JSON string for AUTH message or NULL on error (caller must free)
 */
char* nostr_nip42_create_auth_message(cJSON* auth_event);

/**
 * Validate challenge string format and freshness
 * @param challenge Challenge string to validate
 * @param received_at Time when challenge was received (0 for no time check)
 * @param time_tolerance Maximum age in seconds (0 for default)
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_validate_challenge(const char* challenge, 
                                   time_t received_at,
                                   int time_tolerance);

/**
 * Parse AUTH challenge message from relay
 * @param message Raw message from relay
 * @param challenge_out Output buffer for challenge string
 * @param challenge_size Size of challenge buffer
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_parse_auth_challenge(const char* message,
                                     char* challenge_out,
                                     size_t challenge_size);

// =============================================================================
// SERVER-SIDE FUNCTIONS (for relay implementations)
// =============================================================================

/**
 * Generate cryptographically secure challenge string
 * @param challenge_out Output buffer for challenge (must be at least length*2+1)
 * @param length Desired challenge length in bytes (16-128)
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_generate_challenge(char* challenge_out, size_t length);

/**
 * Verify NIP-42 authentication event
 * @param auth_event Authentication event to verify
 * @param expected_challenge Challenge that was sent to client
 * @param relay_url Expected relay URL
 * @param time_tolerance Maximum timestamp deviation in seconds
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_verify_auth_event(cJSON* auth_event,
                                  const char* expected_challenge,
                                  const char* relay_url,
                                  int time_tolerance);

/**
 * Parse AUTH message from client
 * @param message Raw AUTH message from client
 * @param auth_event_out Output pointer to parsed event (caller must free)
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_parse_auth_message(const char* message, cJSON** auth_event_out);

/**
 * Create "auth-required" error response
 * @param subscription_id Subscription ID (for CLOSED) or NULL (for OK)
 * @param event_id Event ID (for OK) or NULL (for CLOSED)
 * @param reason Human-readable reason
 * @return JSON string for response or NULL on error (caller must free)
 */
char* nostr_nip42_create_auth_required_message(const char* subscription_id,
                                               const char* event_id,
                                               const char* reason);

/**
 * Create "restricted" error response
 * @param subscription_id Subscription ID (for CLOSED) or NULL (for OK)
 * @param event_id Event ID (for OK) or NULL (for CLOSED)  
 * @param reason Human-readable reason
 * @return JSON string for response or NULL on error (caller must free)
 */
char* nostr_nip42_create_restricted_message(const char* subscription_id,
                                            const char* event_id,
                                            const char* reason);

// =============================================================================
// URL NORMALIZATION FUNCTIONS
// =============================================================================

/**
 * Normalize relay URL for comparison (removes trailing slashes, etc.)
 * @param url Original URL
 * @return Normalized URL string or NULL on error (caller must free)
 */
char* nostr_nip42_normalize_url(const char* url);

/**
 * Check if two relay URLs match after normalization
 * @param url1 First URL
 * @param url2 Second URL  
 * @return 1 if URLs match, 0 if they don't, -1 on error
 */
int nostr_nip42_urls_match(const char* url1, const char* url2);

// =============================================================================
// UTILITY FUNCTIONS
// =============================================================================

/**
 * Get string description of authentication state
 * @param state Authentication state
 * @return Human-readable string
 */
const char* nostr_nip42_auth_state_str(nostr_auth_state_t state);

/**
 * Initialize authentication context structure
 * @param ctx Context to initialize
 * @param relay_url Relay URL
 * @param challenge Challenge string
 * @param time_tolerance Time tolerance in seconds
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_init_auth_context(nostr_auth_context_t* ctx,
                                  const char* relay_url,
                                  const char* challenge,
                                  int time_tolerance);

/**
 * Free authentication context structure
 * @param ctx Context to free
 */
void nostr_nip42_free_auth_context(nostr_auth_context_t* ctx);

/**
 * Validate authentication event structure (without signature verification)
 * @param auth_event Event to validate
 * @param relay_url Expected relay URL
 * @param challenge Expected challenge
 * @param time_tolerance Maximum timestamp deviation in seconds  
 * @return NOSTR_SUCCESS or error code
 */
int nostr_nip42_validate_auth_event_structure(cJSON* auth_event,
                                              const char* relay_url,
                                              const char* challenge,
                                              int time_tolerance);

// =============================================================================
// WEBSOCKET CLIENT INTEGRATION
// =============================================================================

// Forward declaration for WebSocket client
struct nostr_ws_client;

/**
 * Authenticate WebSocket client with relay
 * @param client WebSocket client handle
 * @param private_key 32-byte private key for authentication
 * @param time_tolerance Maximum timestamp deviation in seconds (0 for default)
 * @return NOSTR_SUCCESS or error code
 */
int nostr_ws_authenticate(struct nostr_ws_client* client,
                         const unsigned char* private_key,
                         int time_tolerance);

/**
 * Get current authentication state of WebSocket client
 * @param client WebSocket client handle
 * @return Current authentication state
 */
nostr_auth_state_t nostr_ws_get_auth_state(struct nostr_ws_client* client);

/**
 * Check if WebSocket client has stored valid challenge
 * @param client WebSocket client handle
 * @return 1 if valid challenge exists, 0 otherwise
 */
int nostr_ws_has_valid_challenge(struct nostr_ws_client* client);

/**
 * Get stored challenge from WebSocket client
 * @param client WebSocket client handle
 * @param challenge_out Output buffer for challenge
 * @param challenge_size Size of output buffer
 * @return NOSTR_SUCCESS or error code
 */
int nostr_ws_get_challenge(struct nostr_ws_client* client,
                          char* challenge_out,
                          size_t challenge_size);

/**
 * Store challenge in WebSocket client (internal function)
 * @param client WebSocket client handle
 * @param challenge Challenge string to store
 * @return NOSTR_SUCCESS or error code
 */
int nostr_ws_store_challenge(struct nostr_ws_client* client,
                            const char* challenge);

/**
 * Clear authentication state in WebSocket client
 * @param client WebSocket client handle
 * @return NOSTR_SUCCESS or error code
 */
int nostr_ws_clear_auth_state(struct nostr_ws_client* client);

#ifdef __cplusplus
}
#endif

#endif // NIP042_H