/*
 * NIP-21 URI Scheme Test Suite
 * Tests nostr: URI parsing and construction functionality
 * Following TESTS POLICY: Shows expected vs actual values
 */

#define _GNU_SOURCE  // For strdup on Linux
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../nostr_core/nip021.h"
#include "../nostr_core/nostr_common.h"
#include "../nostr_core/utils.h"

// Ensure strdup is declared
#ifndef strdup
extern char *strdup(const char *s);
#endif

// Test counter for tracking progress
static int test_count = 0;
static int passed_tests = 0;

void print_test_header(const char* test_name) {
    test_count++;
    printf("\n=== TEST %d: %s ===\n", test_count, test_name);
}

void print_test_result(int passed, const char* test_name) {
    if (passed) {
        passed_tests++;
        printf("✅ PASS: %s\n", test_name);
    } else {
        printf("❌ FAIL: %s\n", test_name);
    }
}

// Test 1: Parse note URI
int test_parse_note_uri(void) {
    print_test_header("Parse note: URI");

    // First build a valid note URI, then parse it
    unsigned char event_id[32];
    nostr_hex_to_bytes("f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0", event_id, 32);

    char built_uri[200];
    int build_result = nostr_build_uri_note(event_id, built_uri, sizeof(built_uri));
    if (build_result != NOSTR_SUCCESS) {
        printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result));
        return 0;
    }

    printf("Input URI: %s\n", built_uri);

    nostr_uri_result_t result;
    int parse_result = nostr_parse_uri(built_uri, &result);

    printf("Expected: NOSTR_SUCCESS (0)\n");
    printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result));

    if (parse_result != NOSTR_SUCCESS) {
        return 0;
    }

    printf("Expected type: NOSTR_URI_NOTE\n");
    printf("Actual type: %d\n", result.type);

    if (result.type != NOSTR_URI_NOTE) {
        return 0;
    }

    printf("Expected event ID to be set\n");
    printf("Event ID present: %s\n", result.data.event_id[0] ? "yes" : "no");

    // Verify the parsed event ID matches the original
    int event_id_match = (memcmp(result.data.event_id, event_id, 32) == 0);
    printf("Event ID matches original: %s\n", event_id_match ? "yes" : "no");

    return (result.type == NOSTR_URI_NOTE && event_id_match);
}

// Test 2: Parse nprofile URI
int test_parse_nprofile_uri(void) {
    print_test_header("Parse nprofile: URI");

    // First build a valid nprofile URI, then parse it
    unsigned char pubkey[32];
    nostr_hex_to_bytes("aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4", pubkey, 32);
    const char* relays[] = {"wss://relay.example.com"};

    char built_uri[300];
    int build_result = nostr_build_uri_nprofile(pubkey, relays, 1, built_uri, sizeof(built_uri));
    if (build_result != NOSTR_SUCCESS) {
        printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result));
        return 0;
    }

    printf("Input URI: %s\n", built_uri);

    nostr_uri_result_t result;
    int parse_result = nostr_parse_uri(built_uri, &result);

    printf("Expected: NOSTR_SUCCESS (0)\n");
    printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result));

    if (parse_result != NOSTR_SUCCESS) {
        return 0;
    }

    printf("Expected type: NOSTR_URI_NPROFILE\n");
    printf("Actual type: %d\n", result.type);

    if (result.type != NOSTR_URI_NPROFILE) {
        return 0;
    }

    // Verify the parsed pubkey matches the original
    int pubkey_match = (memcmp(result.data.nprofile.pubkey, pubkey, 32) == 0);
    printf("Pubkey matches original: %s\n", pubkey_match ? "yes" : "no");

    // Verify relay count
    printf("Expected relay count: 1\n");
    printf("Actual relay count: %d\n", result.data.nprofile.relay_count);

    return (result.type == NOSTR_URI_NPROFILE && pubkey_match && result.data.nprofile.relay_count == 1);
}

// Test 3: Parse nevent URI
int test_parse_nevent_uri(void) {
    print_test_header("Parse nevent: URI");

    // First build a valid nevent URI, then parse it
    unsigned char event_id[32];
    nostr_hex_to_bytes("f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0", event_id, 32);
    const char* relays[] = {"wss://relay.example.com"};

    char built_uri[400];
    int build_result = nostr_build_uri_nevent(event_id, relays, 1, NULL, 1, 1234567890, built_uri, sizeof(built_uri));
    if (build_result != NOSTR_SUCCESS) {
        printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result));
        return 0;
    }

    printf("Input URI: %s\n", built_uri);

    nostr_uri_result_t result;
    int parse_result = nostr_parse_uri(built_uri, &result);

    printf("Expected: NOSTR_SUCCESS (0)\n");
    printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result));

    if (parse_result != NOSTR_SUCCESS) {
        return 0;
    }

    printf("Expected type: NOSTR_URI_NEVENT\n");
    printf("Actual type: %d\n", result.type);

    if (result.type != NOSTR_URI_NEVENT) {
        return 0;
    }

    // Verify the parsed event ID matches the original
    int event_id_match = (memcmp(result.data.nevent.event_id, event_id, 32) == 0);
    printf("Event ID matches original: %s\n", event_id_match ? "yes" : "no");

    // Verify kind
    printf("Expected kind: 1\n");
    printf("Actual kind: %d\n", result.data.nevent.kind ? *result.data.nevent.kind : -1);

    // Verify relay count
    printf("Expected relay count: 1\n");
    printf("Actual relay count: %d\n", result.data.nevent.relay_count);

    return (result.type == NOSTR_URI_NEVENT && event_id_match && result.data.nevent.relay_count == 1);
}

// Test 4: Parse naddr URI
int test_parse_naddr_uri(void) {
    print_test_header("Parse naddr: URI");

    // First build a valid naddr URI, then parse it
    const char* identifier = "draft";
    unsigned char pubkey[32];
    nostr_hex_to_bytes("aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4", pubkey, 32);
    const char* relays[] = {"wss://relay.example.com"};

    char built_uri[400];
    int build_result = nostr_build_uri_naddr(identifier, pubkey, 30023, relays, 1, built_uri, sizeof(built_uri));
    if (build_result != NOSTR_SUCCESS) {
        printf("Failed to build URI for testing: %d (%s)\n", build_result, nostr_strerror(build_result));
        return 0;
    }

    printf("Input URI: %s\n", built_uri);

    nostr_uri_result_t result;
    int parse_result = nostr_parse_uri(built_uri, &result);

    printf("Expected: NOSTR_SUCCESS (0)\n");
    printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result));

    if (parse_result != NOSTR_SUCCESS) {
        return 0;
    }

    printf("Expected type: NOSTR_URI_NADDR\n");
    printf("Actual type: %d\n", result.type);

    if (result.type != NOSTR_URI_NADDR) {
        return 0;
    }

    // Verify the parsed identifier matches the original
    int identifier_match = (strcmp(result.data.naddr.identifier, identifier) == 0);
    printf("Identifier matches original: %s\n", identifier_match ? "yes" : "no");

    // Verify kind
    printf("Expected kind: 30023\n");
    printf("Actual kind: %d\n", result.data.naddr.kind);

    // Verify relay count
    printf("Expected relay count: 1\n");
    printf("Actual relay count: %d\n", result.data.naddr.relay_count);

    return (result.type == NOSTR_URI_NADDR && identifier_match && result.data.naddr.relay_count == 1);
}

// Test 5: Invalid URI (wrong prefix)
int test_invalid_uri_prefix(void) {
    print_test_header("Invalid URI - Wrong Prefix");

    const char* uri = "bitcoin:note1example";
    printf("Input URI: %s\n", uri);

    nostr_uri_result_t result;
    int parse_result = nostr_parse_uri(uri, &result);

    printf("Expected: NOSTR_ERROR_INVALID_INPUT (-1)\n");
    printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result));

    return (parse_result == NOSTR_ERROR_INVALID_INPUT);
}

// Test 6: Invalid URI (missing colon)
int test_invalid_uri_no_colon(void) {
    print_test_header("Invalid URI - No Colon");

    const char* uri = "nostrnote1example";
    printf("Input URI: %s\n", uri);

    nostr_uri_result_t result;
    int parse_result = nostr_parse_uri(uri, &result);

    printf("Expected: NOSTR_ERROR_INVALID_INPUT (-1)\n");
    printf("Actual: %d (%s)\n", parse_result, nostr_strerror(parse_result));

    return (parse_result == NOSTR_ERROR_INVALID_INPUT);
}

// Test 7: Build note URI
int test_build_note_uri(void) {
    print_test_header("Build note: URI");

    unsigned char event_id[32];
    nostr_hex_to_bytes("f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0", event_id, 32);
    printf("Input event ID: f1e582c90f071c0110cc5bcac2dcc6d8c32250e3cc26fcbe93470d918f2ffaf0\n");

    char uri[200];
    int result = nostr_build_uri_note(event_id, uri, sizeof(uri));
    printf("Build result: %d (%s)\n", result, nostr_strerror(result));

    if (result != NOSTR_SUCCESS) {
        return 0;
    }

    printf("Built URI: %s\n", uri);
    int success = (strncmp(uri, "nostr:note1", 11) == 0);
    printf("Expected: URI starts with 'nostr:note1'\n");
    printf("Actual: %s\n", success ? "yes" : "no");

    return success;
}

// Test 8: Build nprofile URI
int test_build_nprofile_uri(void) {
    print_test_header("Build nprofile: URI");

    unsigned char pubkey[32];
    nostr_hex_to_bytes("aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4", pubkey, 32);
    const char* relays[] = {"wss://relay.example.com", "wss://relay2.example.com"};
    printf("Input pubkey: aa4fc8665f5696e33db7e1a572e3b0f5b3d615837b0f362dcb1c8068b098c7b4\n");

    char uri[300];
    int result = nostr_build_uri_nprofile(pubkey, relays, 2, uri, sizeof(uri));
    printf("Build result: %d (%s)\n", result, nostr_strerror(result));

    if (result != NOSTR_SUCCESS) {
        return 0;
    }

    printf("Built URI: %s\n", uri);
    int success = (strncmp(uri, "nostr:nprofile1", 14) == 0);
    printf("Expected: URI starts with 'nostr:nprofile1'\n");
    printf("Actual: %s\n", success ? "yes" : "no");

    return success;
}

int main(void) {
    printf("=== NIP-21 URI Scheme Test Suite ===\n");
    printf("Following TESTS POLICY: Shows expected vs actual values\n");

    // Initialize crypto library
    if (nostr_init() != NOSTR_SUCCESS) {
        printf("❌ Failed to initialize nostr library\n");
        return 1;
    }

    int all_passed = 1;
    int test_result;

    // Valid URI parsing tests
    test_result = test_parse_note_uri();
    print_test_result(test_result, "Parse note: URI");
    if (!test_result) all_passed = 0;

    test_result = test_parse_nprofile_uri();
    print_test_result(test_result, "Parse nprofile: URI");
    if (!test_result) all_passed = 0;

    test_result = test_parse_nevent_uri();
    print_test_result(test_result, "Parse nevent: URI");
    if (!test_result) all_passed = 0;

    test_result = test_parse_naddr_uri();
    print_test_result(test_result, "Parse naddr: URI");
    if (!test_result) all_passed = 0;

    // Invalid URI tests
    test_result = test_invalid_uri_prefix();
    print_test_result(test_result, "Invalid URI - Wrong Prefix");
    if (!test_result) all_passed = 0;

    test_result = test_invalid_uri_no_colon();
    print_test_result(test_result, "Invalid URI - No Colon");
    if (!test_result) all_passed = 0;

    // URI building tests
    test_result = test_build_note_uri();
    print_test_result(test_result, "Build note: URI");
    if (!test_result) all_passed = 0;

    test_result = test_build_nprofile_uri();
    print_test_result(test_result, "Build nprofile: URI");
    if (!test_result) all_passed = 0;

    // Summary
    printf("\n=== TEST SUMMARY ===\n");
    printf("Total tests: %d\n", test_count);
    printf("Passed: %d\n", passed_tests);
    printf("Failed: %d\n", test_count - passed_tests);

    if (all_passed) {
        printf("🎉 ALL TESTS PASSED! NIP-21 URI scheme implementation is working correctly.\n");
    } else {
        printf("❌ SOME TESTS FAILED. Please review the output above.\n");
    }

    nostr_cleanup();
    return all_passed ? 0 : 1;
}