/*
 * NIP-17 Private Direct Messages Test Program
 *
 * Tests the complete NIP-17 DM flow using synchronous relay operations:
 * 1. Generate sender and recipient keypairs
 * 2. Create a DM from sender to recipient
 * 3. Publish the gift-wrapped DM to relay
 * 4. Subscribe to receive the DM back
 * 5. Decrypt and verify the received DM
 */

#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L

// Enable debug output to see all relay messages
#define NOSTR_DEBUG_ENABLED

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

// Forward declarations for crypto functions
int nostr_secp256k1_get_random_bytes(unsigned char* buf, size_t len);

// Test configuration
#define RELAY_URL "wss://relay.laantungir.net"
#define TEST_TIMEOUT_MS 5000

// Progress callback for publishing
void publish_progress_callback(const char* relay_url, const char* status,
                              const char* message, int success_count,
                              int total_relays, int completed_relays, void* user_data) {
    (void)user_data;

    if (relay_url) {
        printf("📡 PUBLISH [%s]: %s", relay_url, status);
        if (message) {
            printf(" - %s", message);
        }
        printf(" (%d/%d completed, %d successful)\n", completed_relays, total_relays, success_count);
    } else {
        printf("📡 PUBLISH COMPLETE: %d/%d successful\n", success_count, total_relays);
    }
}

// Progress callback for querying/subscribing
void query_progress_callback(const char* relay_url, const char* status,
                            const char* event_id, int event_count,
                            int total_relays, int completed_relays, void* user_data) {
    (void)user_data;

    if (relay_url) {
        printf("🔍 QUERY [%s]: %s", relay_url, status);
        if (event_id) {
            printf(" - Event: %.12s...", event_id);
        }
        if (event_count > 0) {
            printf(" (%d events)", event_count);
        }
        printf(" (%d/%d completed)\n", completed_relays, total_relays);
    } else {
        printf("🔍 QUERY COMPLETE: %d events found\n", event_count);
    }
}

/**
 * Generate a random keypair for testing
 */
void generate_test_keypair(unsigned char* private_key, char* pubkey_hex) {
    // Generate random private key
    if (nostr_secp256k1_get_random_bytes(private_key, 32) != 1) {
        fprintf(stderr, "Failed to generate random private key\n");
        exit(1);
    }

    // Derive public key
    unsigned char public_key[32];
    if (nostr_ec_public_key_from_private_key(private_key, public_key) != 0) {
        fprintf(stderr, "Failed to derive public key\n");
        exit(1);
    }

    // Convert to hex
    nostr_bytes_to_hex(public_key, 32, pubkey_hex);
}

/**
 * Main test function
 */
int main(int argc, char* argv[]) {
    (void)argc; // Suppress unused parameter warning
    (void)argv; // Suppress unused parameter warning

    printf("🧪 NIP-17 Private Direct Messages Test (Synchronous)\n");
    printf("=================================================\n\n");

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

    // Generate keypairs
    unsigned char sender_privkey[32];
    unsigned char recipient_privkey[32];
    char sender_pubkey_hex[65];
    char recipient_pubkey_hex[65];

    printf("🔑 Generating keypairs...\n");
    generate_test_keypair(sender_privkey, sender_pubkey_hex);
    generate_test_keypair(recipient_privkey, recipient_pubkey_hex);

    printf("📤 Sender pubkey: %s\n", sender_pubkey_hex);
    printf("📥 Recipient pubkey: %s\n", recipient_pubkey_hex);
    printf("\n");

    // Create DM event with timestamp
    printf("💬 Creating DM event...\n");
    time_t now = time(NULL);
    char test_message[256];
    snprintf(test_message, sizeof(test_message),
             "Hello from NIP-17! This is a private direct message sent at %ld", now);

    const char* recipient_pubkeys[] = {recipient_pubkey_hex};
    cJSON* dm_event = nostr_nip17_create_chat_event(
        test_message,
        recipient_pubkeys,
        1,
        "NIP-17 Test",
        NULL,  // no reply
        RELAY_URL,
        sender_pubkey_hex
    );

    if (!dm_event) {
        fprintf(stderr, "Failed to create DM event\n");
        return 1;
    }

    printf("📝 Created DM event (kind 14)\n");

    // Send DM (create gift wraps)
    printf("🎁 Creating gift wraps...\n");
    cJSON* gift_wraps[10];  // Max 10 gift wraps
    int gift_wrap_count = nostr_nip17_send_dm(
        dm_event,
        recipient_pubkeys,
        1,
        sender_privkey,
        gift_wraps,
        10
    );

    cJSON_Delete(dm_event);  // Original DM event no longer needed

    if (gift_wrap_count <= 0) {
        fprintf(stderr, "Failed to create gift wraps\n");
        return 1;
    }

    printf("✅ Created %d gift wrap(s)\n", gift_wrap_count);

    // Print the gift wrap JSON
    printf("\n📄 Gift wrap event JSON:\n");
    printf("========================\n");
    char* gift_wrap_json = cJSON_Print(gift_wraps[0]);
    printf("%s\n", gift_wrap_json);
    free(gift_wrap_json);

    // PHASE 1: Publish the gift wrap to relay
    printf("\n📤 PHASE 1: Publishing gift wrap to relay\n");
    printf("==========================================\n");

    const char* relay_urls[] = {RELAY_URL};
    int success_count = 0;
    publish_result_t* publish_results = synchronous_publish_event_with_progress(
        relay_urls,
        1,  // single relay
        gift_wraps[0],  // Send the first gift wrap
        &success_count,
        10,  // 10 second timeout
        publish_progress_callback,
        NULL,  // no user data
        0,     // NIP-42 disabled
        NULL   // no private key for auth
    );

    if (!publish_results || success_count != 1) {
        fprintf(stderr, "❌ Failed to publish gift wrap (success_count: %d)\n", success_count);
        // Clean up gift wraps
        for (int i = 0; i < gift_wrap_count; i++) {
            cJSON_Delete(gift_wraps[i]);
        }
        if (publish_results) free(publish_results);
        return 1;
    }

    printf("✅ Successfully published gift wrap!\n");

    // Clean up publish results and gift wraps
    free(publish_results);
    for (int i = 0; i < gift_wrap_count; i++) {
        cJSON_Delete(gift_wraps[i]);
    }

    // Small delay to let the relay process the event
    printf("⏳ Waiting 2 seconds for relay to process...\n");
    sleep(2);

    // PHASE 2: Subscribe to receive the DM back
    printf("\n📥 PHASE 2: Subscribing to receive DM back\n");
    printf("===========================================\n");

    // Create filter for gift wraps addressed to recipient
    cJSON* filter = cJSON_CreateObject();
    cJSON* kinds = cJSON_CreateArray();
    cJSON_AddItemToArray(kinds, cJSON_CreateNumber(1059));  // Gift wrap kind
    cJSON_AddItemToObject(filter, "kinds", kinds);

    // Filter for gift wraps with p tag matching recipient
    cJSON* p_tags = cJSON_CreateArray();
    cJSON_AddItemToArray(p_tags, cJSON_CreateString(recipient_pubkey_hex));
    cJSON_AddItemToObject(filter, "#p", p_tags);

    // Print the subscription filter JSON
    printf("📄 Subscription filter JSON:\n");
    printf("============================\n");
    char* filter_json = cJSON_Print(filter);
    printf("%s\n", filter_json);
    free(filter_json);

    int query_result_count = 0;
    cJSON** query_results = synchronous_query_relays_with_progress(
        relay_urls,
        1,  // single relay
        filter,
        RELAY_QUERY_ALL_RESULTS,  // Get all matching events
        &query_result_count,
        10,  // 10 second timeout per relay
        query_progress_callback,
        NULL,  // no user data
        0,     // NIP-42 disabled
        NULL   // no private key for auth
    );

    cJSON_Delete(filter);  // Clean up filter

    if (!query_results || query_result_count == 0) {
        fprintf(stderr, "❌ No DM events received back from relay\n");
        if (query_results) free(query_results);
        return 1;
    }

    printf("✅ Received %d event(s) from relay!\n", query_result_count);

    // Process the received events
    printf("\n🔍 PHASE 3: Processing received events\n");
    printf("=====================================\n");

    int dm_found = 0;
    cJSON* received_dm = NULL;

    for (int i = 0; i < query_result_count; i++) {
        cJSON* event = query_results[i];
        cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
        cJSON* id_item = cJSON_GetObjectItem(event, "id");

        if (kind_item && cJSON_IsNumber(kind_item) && cJSON_GetNumberValue(kind_item) == 1059) {
            printf("🎁 Found gift wrap event: %.12s...\n",
                   id_item && cJSON_IsString(id_item) ? cJSON_GetStringValue(id_item) : "unknown");

            // Try to decrypt this gift wrap
            cJSON* decrypted_dm = nostr_nip17_receive_dm(event, recipient_privkey);
            if (decrypted_dm) {
                printf("✅ Successfully decrypted gift wrap!\n");

                // Verify the decrypted DM
                cJSON* content_item = cJSON_GetObjectItem(decrypted_dm, "content");
                cJSON* dm_kind_item = cJSON_GetObjectItem(decrypted_dm, "kind");
                cJSON* pubkey_item = cJSON_GetObjectItem(decrypted_dm, "pubkey");

                if (content_item && dm_kind_item && pubkey_item) {
                    const char* decrypted_content = cJSON_GetStringValue(content_item);
                    int decrypted_kind = (int)cJSON_GetNumberValue(dm_kind_item);
                    const char* decrypted_pubkey = cJSON_GetStringValue(pubkey_item);

                    printf("📧 Decrypted DM:\n");
                    printf("   Kind: %d\n", decrypted_kind);
                    printf("   From: %s\n", decrypted_pubkey);
                    printf("   Content: %s\n", decrypted_content);

                    // Verify the DM content (check that it contains our message with timestamp)
                    int content_ok = strstr(decrypted_content, "Hello from NIP-17! This is a private direct message sent at ") != NULL;

                    if (decrypted_kind == 14 &&
                        content_ok &&
                        strlen(decrypted_content) >= 64 && // Should be at least as long as the prefix
                        strcmp(decrypted_pubkey, sender_pubkey_hex) == 0) {

                        printf("✅ DM verification successful!\n");
                        dm_found = 1;
                        received_dm = decrypted_dm;  // Keep reference for cleanup
                        break;  // Found our DM, no need to check more
                    } else {
                        printf("❌ DM verification failed\n");
                        cJSON_Delete(decrypted_dm);
                    }
                } else {
                    printf("❌ Invalid decrypted DM structure\n");
                    cJSON_Delete(decrypted_dm);
                }
            } else {
                printf("❌ Failed to decrypt gift wrap\n");
            }
        }
    }

    // Clean up query results
    for (int i = 0; i < query_result_count; i++) {
        cJSON_Delete(query_results[i]);
    }
    free(query_results);

    if (!dm_found) {
        fprintf(stderr, "❌ Could not find or decrypt the expected DM\n");
        return 1;
    }

    printf("\n🎉 NIP-17 synchronous test completed successfully!\n");

    // Cleanup
    if (received_dm) {
        cJSON_Delete(received_dm);
    }
    nostr_cleanup();

    return 0;
}