/*
 * Manual Proof of Work Loop Test
 * 
 * Creates an event and manually mines it by incrementing nonce
 * until target difficulty is reached. Shows each iteration.
 */

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

// Helper function to count leading zero bits (from NIP-13)
static int zero_bits(unsigned char b) {
    int n = 0;
    
    if (b == 0)
        return 8;
    
    while (b >>= 1)
        n++;
    
    return 7-n;
}

// Count leading zero bits in hash (from NIP-13)
static int count_leading_zero_bits(unsigned char *hash) {
    int bits, total, i;
    for (i = 0, total = 0; i < 32; i++) {
        bits = zero_bits(hash[i]);
        total += bits;
        if (bits != 8)
            break;
    }
    return total;
}

int main() {
    // Initialize library
    if (nostr_init() != NOSTR_SUCCESS) {
        fprintf(stderr, "Failed to initialize nostr library\n");
        return 1;
    }
    
    // Generate test keypair
    unsigned char private_key[32];
    unsigned char public_key[32];
    
    if (nostr_generate_keypair(private_key, public_key) != NOSTR_SUCCESS) {
        fprintf(stderr, "Failed to generate keypair\n");
        nostr_cleanup();
        return 1;
    }
    
    printf("=== Manual Proof of Work Mining (Target Difficulty: 8) ===\n\n");
    
    // Create base event content
    const char* content = "Proof of Work Test";
    int kind = 1;
    time_t created_at = time(NULL);
    
    // Target difficulty
    const int target_difficulty = 20;
    uint64_t nonce = 0;
    int max_attempts = 10000000000;
    
    printf("Mining event with target difficulty %d...\n\n", target_difficulty);
    
    // Mining loop
    for (int attempt = 0; attempt < max_attempts; attempt++) {
        // Create tags array with current nonce
        cJSON* tags = cJSON_CreateArray();
        if (!tags) {
            fprintf(stderr, "Failed to create tags array\n");
            break;
        }
        
        // Add nonce tag: ["nonce", "<nonce>", "<target_difficulty>"]
        cJSON* nonce_tag = cJSON_CreateArray();
        char nonce_str[32];
        char difficulty_str[16];
        snprintf(nonce_str, sizeof(nonce_str), "%llu", (unsigned long long)nonce);
        snprintf(difficulty_str, sizeof(difficulty_str), "%d", target_difficulty);
        
        cJSON_AddItemToArray(nonce_tag, cJSON_CreateString("nonce"));
        cJSON_AddItemToArray(nonce_tag, cJSON_CreateString(nonce_str));
        cJSON_AddItemToArray(nonce_tag, cJSON_CreateString(difficulty_str));
        cJSON_AddItemToArray(tags, nonce_tag);
        
        // Create and sign event with current nonce
        cJSON* event = nostr_create_and_sign_event(kind, content, tags, private_key, created_at);
        cJSON_Delete(tags);
        
        if (!event) {
            fprintf(stderr, "Failed to create event at nonce %llu\n", (unsigned long long)nonce);
            nonce++;
            continue;
        }
        
        // Get event ID
        cJSON* id_item = cJSON_GetObjectItem(event, "id");
        if (!id_item || !cJSON_IsString(id_item)) {
            fprintf(stderr, "Failed to get event ID at nonce %llu\n", (unsigned long long)nonce);
            cJSON_Delete(event);
            nonce++;
            continue;
        }
        
        const char* event_id = cJSON_GetStringValue(id_item);
        
        // Convert hex ID to bytes and count leading zero bits
        unsigned char hash[32];
        if (nostr_hex_to_bytes(event_id, hash, 32) != NOSTR_SUCCESS) {
            fprintf(stderr, "Failed to convert event ID to bytes at nonce %llu\n", (unsigned long long)nonce);
            cJSON_Delete(event);
            nonce++;
            continue;
        }
        
        int current_difficulty = count_leading_zero_bits(hash);
        
        // Print current attempt
        printf("Nonce %llu: ID = %.16s... (difficulty: %d)", 
               (unsigned long long)nonce, event_id, current_difficulty);
        
        // Check if we've reached target difficulty
        if (current_difficulty >= target_difficulty) {
            printf(" ✓ SUCCESS!\n\n");
            
            // Print final successful event
            printf("=== SUCCESSFUL EVENT ===\n");
            char* final_json = cJSON_Print(event);
            if (final_json) {
                printf("%s\n", final_json);
                free(final_json);
            }
            
            printf("\n🎉 Mining completed!\n");
            printf("   Attempts: %d\n", attempt + 1);
            printf("   Final nonce: %llu\n", (unsigned long long)nonce);
            printf("   Final difficulty: %d (target was %d)\n", current_difficulty, target_difficulty);
            
            cJSON_Delete(event);
            nostr_cleanup();
            return 0;
        } else {
            printf(" (need %d)\n", target_difficulty);
        }
        
        cJSON_Delete(event);
        nonce++;
    }
    
    // If we reach here, we've exceeded max attempts
    printf("\n❌ Mining failed after %d attempts\n", max_attempts);
    printf("Consider increasing max_attempts or reducing target_difficulty\n");
    
    nostr_cleanup();
    return 1;
}
