/*
 * NOSTR Event Generation Test Suite
 * Tests complete workflow from mnemonic to signed event using specific test vectors
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "../nostr_core/nostr_core.h"
#include "../cjson/cJSON.h"

// Test vector structure
typedef struct {
    const char* mnemonic;
    const char* expected_nsec_hex;
    const char* expected_nsec;
    const char* expected_npub_hex;
    const char* expected_npub;
    const char* name;
} test_vector_t;

// Test vectors to validate against
static const test_vector_t TEST_VECTORS[] = {
    {
        .name = "Vector 1",
        .mnemonic = "fetch risk mention yellow cluster hunt voyage acquire leader caution romance solid",
        .expected_nsec_hex = "b46173ac0cc222f73246d6be63f5c0bd90d92b118f99f582cd11d077490d0794",
        .expected_nsec = "nsec1k3sh8tqvcg30wvjx66lx8awqhkgdj2c337vltqkdz8g8wjgdq72q3mrze9",
        .expected_npub_hex = "a11258677dd416ca4c9e352e0e02ad2d8784a18c3a963604d0c63dc7b74eec66",
        .expected_npub = "npub15yf9sema6stv5ny7x5hquq4d9krcfgvv82trvpxscc7u0d6wa3nqmvcv3a"
    },
    {
        .name = "Vector 2",
        .mnemonic = "leader monkey parrot ring guide accident before fence cannon height naive bean",
        .expected_nsec_hex = "7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a",
        .expected_nsec = "nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp",
        .expected_npub_hex = "17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917",
        .expected_npub = "npub1zutzeysacnf9rru6zqwmxd54mud0k44tst6l70ja5mhv8jjumytsd2x7nu"
    },
    {
        .name = "Vector 3",
        .mnemonic = "what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade",
        .expected_nsec_hex = "c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add",
        .expected_nsec = "nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel",
        .expected_npub_hex = "d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573",
        .expected_npub = "npub16sdj9zv4f8sl85e45vgq9n7nsgt5qphpvmf7vk8r5hhvmdjxx4es8rq74h"
    }
};

static const size_t NUM_TEST_VECTORS = sizeof(TEST_VECTORS) / sizeof(TEST_VECTORS[0]);

// Constants for event generation test
static const uint32_t TEST_CREATED_AT = 1698623783;
static const char* TEST_CONTENT = "Hello";

// Expected events for each test vector
typedef struct {
    const char* expected_event_id;
    const char* expected_signature;
    const char* expected_json;
} expected_event_t;

static const expected_event_t EXPECTED_EVENTS[] = {
    {
        // Vector 1 expected event
        .expected_event_id = "c790e29519cc43ad87a4e061c36b4740cf1085e2c9eabb6971ea97f3859eb008",
        .expected_signature = "9acb3e409a8b329316bd4184ad74a50db7764a4370ad863f97fb37858d87c380c9299a7adef19dfd29481f51eb81e28ebba2a6d2bbcc4085a1b07ca8339e8d0c",
        .expected_json = "{\n"
                        "\t\"pubkey\":\t\"a11258677dd416ca4c9e352e0e02ad2d8784a18c3a963604d0c63dc7b74eec66\",\n"
                        "\t\"created_at\":\t1698623783,\n"
                        "\t\"kind\":\t1,\n"
                        "\t\"tags\":\t[],\n"
                        "\t\"content\":\t\"Hello\",\n"
                        "\t\"id\":\t\"c790e29519cc43ad87a4e061c36b4740cf1085e2c9eabb6971ea97f3859eb008\",\n"
                        "\t\"sig\":\t\"9acb3e409a8b329316bd4184ad74a50db7764a4370ad863f97fb37858d87c380c9299a7adef19dfd29481f51eb81e28ebba2a6d2bbcc4085a1b07ca8339e8d0c\"\n"
                        "}"
    },
    {
        // Vector 2 expected event
        .expected_event_id = "e28fda46caa56eb6f62c7871409e6c76cd43a47fca14878b91e49d8ee8e52c27",
        .expected_signature = "7a7ce178e18b1065a9642985a3fb815ed52772c34fc6e67515de012558968f6428509b9cf93cf6faf17db387b833196a5be48ed1154c1c2dffb1c30293318e3d",
        .expected_json = "{\n"
                        "\t\"pubkey\":\t\"17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917\",\n"
                        "\t\"created_at\":\t1698623783,\n"
                        "\t\"kind\":\t1,\n"
                        "\t\"tags\":\t[],\n"
                        "\t\"content\":\t\"Hello\",\n"
                        "\t\"id\":\t\"e28fda46caa56eb6f62c7871409e6c76cd43a47fca14878b91e49d8ee8e52c27\",\n"
                        "\t\"sig\":\t\"7a7ce178e18b1065a9642985a3fb815ed52772c34fc6e67515de012558968f6428509b9cf93cf6faf17db387b833196a5be48ed1154c1c2dffb1c30293318e3d\"\n"
                        "}"
    },
    {
        // Vector 3 expected event
        .expected_event_id = "ad349fdb162ea874d8b685e682b9dcc84b5bd72c4efac51e295db39b7623cde0",
        .expected_signature = "11e2280cca6f2e0f638fbf60f8aa744a4c228ba19f4d787a51298ec23be4a226e5046477cf6444a804c81aa08dd287e9647f0b45f8a02700da4a387187d4b3dc",
        .expected_json = "{\n"
                        "\t\"pubkey\":\t\"d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573\",\n"
                        "\t\"created_at\":\t1698623783,\n"
                        "\t\"kind\":\t1,\n"
                        "\t\"tags\":\t[],\n"
                        "\t\"content\":\t\"Hello\",\n"
                        "\t\"id\":\t\"ad349fdb162ea874d8b685e682b9dcc84b5bd72c4efac51e295db39b7623cde0\",\n"
                        "\t\"sig\":\t\"11e2280cca6f2e0f638fbf60f8aa744a4c228ba19f4d787a51298ec23be4a226e5046477cf6444a804c81aa08dd287e9647f0b45f8a02700da4a387187d4b3dc\"\n"
                        "}"
    }
};

// Helper functions
static void print_test_result(const char* test_name, int passed, const char* expected, const char* actual) {
    if (passed) {
        printf("✓ %s: PASSED\n", test_name);
    } else {
        printf("❌ %s: FAILED\n", test_name);
        printf("  Expected: %s\n", expected);
        printf("  Actual:   %s\n", actual);
    }
}

static void bytes_to_hex_lowercase(const unsigned char* bytes, size_t len, char* hex_out) {
    for (size_t i = 0; i < len; i++) {
        sprintf(hex_out + i * 2, "%02x", bytes[i]);
    }
    hex_out[len * 2] = '\0';
}

// Test single vector for mnemonic to keys
static int test_single_vector_mnemonic_to_keys(const test_vector_t* vector, unsigned char* private_key_out, unsigned char* public_key_out) {
    printf("\n=== Testing %s: Mnemonic to Keys ===\n", vector->name);
    printf("Input mnemonic: %s\n", vector->mnemonic);
    printf("Input account: 0\n");
    
    unsigned char private_key[32];
    unsigned char public_key[32];
    
    // Derive keys from mnemonic using account 0
    printf("Calling nostr_derive_keys_from_mnemonic()...\n");
    int ret = nostr_derive_keys_from_mnemonic(vector->mnemonic, 0, private_key, public_key);
    printf("Function returned: %d\n", ret);
    
    if (ret != NOSTR_SUCCESS) {
        printf("❌ Key derivation failed with code: %d\n", ret);
        printf("Expected: Success (0)\n");
        printf("Actual: Error (%d)\n", ret);
        return 0;
    }
    
    // Convert private key to hex (lowercase)
    char nsec_hex[65];
    bytes_to_hex_lowercase(private_key, 32, nsec_hex);
    
    // Convert public key to hex (lowercase) 
    char npub_hex[65];
    bytes_to_hex_lowercase(public_key, 32, npub_hex);
    
    // Test nsecHex
    printf("\nPrivate Key (nsecHex):\n");
    printf("Expected: %s\n", vector->expected_nsec_hex);
    printf("Actual:   %s\n", nsec_hex);
    int nsec_hex_match = (strcmp(nsec_hex, vector->expected_nsec_hex) == 0);
    printf("Result:   %s\n", nsec_hex_match ? "✓ PASS" : "❌ FAIL");
    
    // Test npubHex  
    printf("\nPublic Key (npubHex):\n");
    printf("Expected: %s\n", vector->expected_npub_hex);
    printf("Actual:   %s\n", npub_hex);
    int npub_hex_match = (strcmp(npub_hex, vector->expected_npub_hex) == 0);
    printf("Result:   %s\n", npub_hex_match ? "✓ PASS" : "❌ FAIL");
    
    // Copy keys for use in other tests
    if (private_key_out) memcpy(private_key_out, private_key, 32);
    if (public_key_out) memcpy(public_key_out, public_key, 32);
    
    return nsec_hex_match && npub_hex_match;
}

// Test single vector for nsec encoding
static int test_single_vector_nsec_encoding(const test_vector_t* vector, const unsigned char* private_key) {
    printf("\n=== Testing %s: nsec Encoding ===\n", vector->name);
    
    // Show input private key in hex
    char private_key_hex[65];
    bytes_to_hex_lowercase(private_key, 32, private_key_hex);
    printf("Input private key (hex): %s\n", private_key_hex);
    
    char nsec[100];
    printf("Calling nostr_key_to_bech32() with hrp='nsec'...\n");
    int ret = nostr_key_to_bech32(private_key, "nsec", nsec);
    printf("Function returned: %d\n", ret);
    
    if (ret != NOSTR_SUCCESS) {
        printf("❌ nsec encoding failed with code: %d\n", ret);
        printf("Expected: Success (0)\n");
        printf("Actual: Error (%d)\n", ret);
        return 0;
    }
    
    printf("\nnsec Encoding:\n");
    printf("Expected: %s\n", vector->expected_nsec);
    printf("Actual:   %s\n", nsec);
    int nsec_match = (strcmp(nsec, vector->expected_nsec) == 0);
    printf("Result:   %s\n", nsec_match ? "✓ PASS" : "❌ FAIL");
    
    return nsec_match;
}

// Test single vector for npub encoding
static int test_single_vector_npub_encoding(const test_vector_t* vector, const unsigned char* public_key) {
    printf("\n=== Testing %s: npub Encoding ===\n", vector->name);
    
    char npub[100];
    int ret = nostr_key_to_bech32(public_key, "npub", npub);
    
    if (ret != NOSTR_SUCCESS) {
        printf("❌ npub encoding failed with code: %d\n", ret);
        return 0;
    }
    
    int npub_match = (strcmp(npub, vector->expected_npub) == 0);
    print_test_result("npub encoding", npub_match, vector->expected_npub, npub);
    
    return npub_match;
}

// Test single vector for event generation
static int test_single_vector_event_generation(const test_vector_t* vector, const unsigned char* private_key, size_t vector_index) {
    printf("\n=== Testing %s: Signed Event Generation ===\n", vector->name);
    
    // Create and sign event with fixed timestamp
    cJSON* event = nostr_create_and_sign_event(1, TEST_CONTENT, NULL, 0, private_key, TEST_CREATED_AT);
    
    if (!event) {
        printf("❌ Event creation failed\n");
        return 0;
    }
    
    // Extract event fields
    cJSON* id_item = cJSON_GetObjectItem(event, "id");
    cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
    cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
    cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
    cJSON* content_item = cJSON_GetObjectItem(event, "content");
    cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
    cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
    
    if (!id_item || !pubkey_item || !created_at_item || !kind_item || 
        !content_item || !sig_item || !tags_item) {
        printf("❌ Event missing required fields\n");
        cJSON_Delete(event);
        return 0;
    }
    
    // Validate field types
    if (!cJSON_IsString(id_item) || !cJSON_IsString(pubkey_item) || 
        !cJSON_IsNumber(created_at_item) || !cJSON_IsNumber(kind_item) ||
        !cJSON_IsString(content_item) || !cJSON_IsString(sig_item) ||
        !cJSON_IsArray(tags_item)) {
        printf("❌ Event fields have wrong types\n");
        cJSON_Delete(event);
        return 0;
    }
    
    // Extract values
    const char* event_id = cJSON_GetStringValue(id_item);
    const char* pubkey = cJSON_GetStringValue(pubkey_item);
    uint32_t created_at = (uint32_t)cJSON_GetNumberValue(created_at_item);
    int kind = (int)cJSON_GetNumberValue(kind_item);
    const char* content = cJSON_GetStringValue(content_item);
    const char* signature = cJSON_GetStringValue(sig_item);
    
    // Test each field
    int tests_passed = 0;
    int total_tests = 7;
    
    // Test kind
    if (kind == 1) {
        printf("✓ Event kind: PASSED (1)\n");
        tests_passed++;
    } else {
        printf("❌ Event kind: FAILED (expected 1, got %d)\n", kind);
    }
    
    // Test pubkey - only check for first vector since we have expected values for that one
    if (strcmp(vector->name, "Vector 1") == 0) {
        int pubkey_match = (strcmp(pubkey, vector->expected_npub_hex) == 0);
        print_test_result("Event pubkey", pubkey_match, vector->expected_npub_hex, pubkey);
        if (pubkey_match) tests_passed++;
    } else {
        // For other vectors, just check that pubkey matches the expected public key
        int pubkey_match = (strcmp(pubkey, vector->expected_npub_hex) == 0);
        print_test_result("Event pubkey", pubkey_match, vector->expected_npub_hex, pubkey);
        if (pubkey_match) tests_passed++;
    }
    
    // Test created_at
    if (created_at == TEST_CREATED_AT) {
        printf("✓ Event created_at: PASSED (%u)\n", created_at);
        tests_passed++;
    } else {
        printf("❌ Event created_at: FAILED (expected %u, got %u)\n", TEST_CREATED_AT, created_at);
    }
    
    // Test content
    int content_match = (strcmp(content, TEST_CONTENT) == 0);
    print_test_result("Event content", content_match, TEST_CONTENT, content);
    if (content_match) tests_passed++;
    
    // Test tags (should be empty array)
    int tags_empty = (cJSON_GetArraySize(tags_item) == 0);
    if (tags_empty) {
        printf("✓ Event tags: PASSED (empty array)\n");
        tests_passed++;
    } else {
        printf("❌ Event tags: FAILED (expected empty array, got %d items)\n", 
               cJSON_GetArraySize(tags_item));
    }
    
    // Get expected event for this vector
    const expected_event_t* expected = &EXPECTED_EVENTS[vector_index];
    
    // Test event ID and signature
    int id_match = (strcmp(event_id, expected->expected_event_id) == 0);
    print_test_result("Event ID", id_match, expected->expected_event_id, event_id);
    if (id_match) tests_passed++;
    
    int sig_match = (strcmp(signature, expected->expected_signature) == 0);
    print_test_result("Event signature", sig_match, expected->expected_signature, signature);
    if (sig_match) tests_passed++;
    
    // Print expected vs generated event JSONs side by side
    printf("\n=== EXPECTED EVENT JSON ===\n");
    printf("%s\n", expected->expected_json);
    
    printf("\n=== GENERATED EVENT JSON ===\n");
    char* event_json = cJSON_Print(event);
    if (event_json) {
        printf("%s\n", event_json);
        free(event_json);
    }
    
    cJSON_Delete(event);
    
    printf("\nEvent generation: %d/%d tests passed\n", tests_passed, total_tests);
    return (tests_passed == total_tests);
}

// Test all vectors
static int test_all_vectors() {
    printf("\n=== Testing All Vectors ===\n");
    
    int total_vectors_passed = 0;
    
    for (size_t i = 0; i < NUM_TEST_VECTORS; i++) {
        const test_vector_t* vector = &TEST_VECTORS[i];
        printf("\n" "==========================================\n");
        printf("Testing %s\n", vector->name);
        printf("==========================================\n");
        
        unsigned char private_key[32];
        unsigned char public_key[32];
        
        // Step 1: Test mnemonic to keys
        int keys_passed = test_single_vector_mnemonic_to_keys(vector, private_key, public_key);
        
        // Step 2: Test nsec encoding
        int nsec_passed = test_single_vector_nsec_encoding(vector, private_key);
        
        // Step 3: Test npub encoding
        int npub_passed = test_single_vector_npub_encoding(vector, public_key);
        
        // Step 4: Test event generation (only if keys work)
        int event_passed = 0;
        if (keys_passed) {
            event_passed = test_single_vector_event_generation(vector, private_key, i);
        }
        
        // Summary for this vector
        printf("\n%s Summary:\n", vector->name);
        printf("  Keys:   %s\n", keys_passed ? "✓ PASS" : "❌ FAIL");
        printf("  nsec:   %s\n", nsec_passed ? "✓ PASS" : "❌ FAIL");
        printf("  npub:   %s\n", npub_passed ? "✓ PASS" : "❌ FAIL");
        printf("  Event:  %s\n", event_passed ? "✓ PASS" : "❌ FAIL");
        
        if (keys_passed && nsec_passed && npub_passed && event_passed) {
            printf("  Overall: ✓ PASS\n");
            total_vectors_passed++;
        } else {
            printf("  Overall: ❌ FAIL\n");
        }
    }
    
    printf("\n" "==========================================\n");
    printf("FINAL RESULTS: %d/%zu vectors passed\n", total_vectors_passed, NUM_TEST_VECTORS);
    printf("==========================================\n");
    
    return (total_vectors_passed == (int)NUM_TEST_VECTORS);
}

int main() {
    printf("NOSTR Event Generation Test Suite\n");
    printf("=================================\n");
    printf("Testing against multiple test vectors for ecosystem compatibility\n");
    
    // Initialize NOSTR library
    if (nostr_init() != NOSTR_SUCCESS) {
        printf("❌ Failed to initialize NOSTR library\n");
        return 1;
    }
    
    // Run all vector tests
    int success = test_all_vectors();
    
    // Print final results
    printf("\n=================================\n");
    if (success) {
        printf("🎉 ALL TEST VECTORS PASSED!\n");
        printf("✅ Your NOSTR implementation produces the exact same results as all test vectors\n");
        printf("✅ This confirms compatibility with other NOSTR tools\n");
    } else {
        printf("❌ SOME TEST VECTORS FAILED\n");
        printf("❌ Your implementation produces different results than expected\n");
        printf("❌ This indicates compatibility issues with other NOSTR tools\n");
        
        printf("\nFor debugging purposes, review the detailed output above to see:\n");
        printf("  - Which vectors passed/failed\n");
        printf("  - Expected vs actual values for each test\n");
        printf("  - Whether the issue is in key derivation, encoding, or event generation\n");
    }
    
    // Cleanup
    nostr_cleanup();
    
    return success ? 0 : 1;
}
