// NIP-13 Proof of Work validation module
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "../nostr_core_lib/cjson/cJSON.h"
#include "../nostr_core_lib/nostr_core/nostr_core.h"
#include "../nostr_core_lib/nostr_core/nip013.h"
#include "config.h"

// Forward declarations for logging functions
void log_info(const char* message);
void log_success(const char* message);
void log_error(const char* message);
void log_warning(const char* message);

// NIP-13 PoW configuration structure
struct pow_config {
    int enabled;                    // 0 = disabled, 1 = enabled
    int min_pow_difficulty;         // Minimum required difficulty (0 = no requirement)
    int validation_flags;           // Bitflags for validation options
    int require_nonce_tag;          // 1 = require nonce tag presence
    int reject_lower_targets;       // 1 = reject if committed < actual difficulty
    int strict_format;              // 1 = enforce strict nonce tag format
    int anti_spam_mode;             // 1 = full anti-spam validation
};

// Initialize PoW configuration using configuration system
void init_pow_config() {

    // Get all config values first (without holding mutex to avoid deadlock)
    int pow_enabled = get_config_bool("pow_enabled", 1);
    int pow_min_difficulty = get_config_int("pow_min_difficulty", 0);
    const char* pow_mode = get_config_value("pow_mode");

    pthread_mutex_lock(&g_unified_cache.cache_lock);

    // Load PoW settings from configuration system
    g_unified_cache.pow_config.enabled = pow_enabled;
    g_unified_cache.pow_config.min_pow_difficulty = pow_min_difficulty;

    // Configure PoW mode
    if (pow_mode) {
        if (strcmp(pow_mode, "strict") == 0) {
            g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_ANTI_SPAM | NOSTR_POW_STRICT_FORMAT;
            g_unified_cache.pow_config.require_nonce_tag = 1;
            g_unified_cache.pow_config.reject_lower_targets = 1;
            g_unified_cache.pow_config.strict_format = 1;
            g_unified_cache.pow_config.anti_spam_mode = 1;
        } else if (strcmp(pow_mode, "full") == 0) {
            g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_FULL;
            g_unified_cache.pow_config.require_nonce_tag = 1;
        } else if (strcmp(pow_mode, "basic") == 0) {
            g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_BASIC;
        } else if (strcmp(pow_mode, "disabled") == 0) {
            g_unified_cache.pow_config.enabled = 0;
        }
        free((char*)pow_mode); // Free dynamically allocated string
    } else {
        // Default to basic mode
        g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_BASIC;
    }

    pthread_mutex_unlock(&g_unified_cache.cache_lock);
}

// Validate event Proof of Work according to NIP-13
int validate_event_pow(cJSON* event, char* error_message, size_t error_size) {
    pthread_mutex_lock(&g_unified_cache.cache_lock);
    int enabled = g_unified_cache.pow_config.enabled;
    int min_pow_difficulty = g_unified_cache.pow_config.min_pow_difficulty;
    int validation_flags = g_unified_cache.pow_config.validation_flags;
    pthread_mutex_unlock(&g_unified_cache.cache_lock);

    if (!enabled) {
        return 0; // PoW validation disabled
    }

    if (!event) {
        snprintf(error_message, error_size, "pow: null event");
        return NOSTR_ERROR_INVALID_INPUT;
    }

    // If min_pow_difficulty is 0, only validate events that have nonce tags
    // This allows events without PoW when difficulty requirement is 0
    if (min_pow_difficulty == 0) {
        cJSON* tags = cJSON_GetObjectItem(event, "tags");
        int has_nonce_tag = 0;

        if (tags && cJSON_IsArray(tags)) {
            cJSON* tag = NULL;
            cJSON_ArrayForEach(tag, tags) {
                if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
                    cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
                    if (cJSON_IsString(tag_name)) {
                        const char* name = cJSON_GetStringValue(tag_name);
                        if (name && strcmp(name, "nonce") == 0) {
                            has_nonce_tag = 1;
                            break;
                        }
                    }
                }
            }
        }

        // If no minimum difficulty required and no nonce tag, skip PoW validation
        if (!has_nonce_tag) {
            return 0; // Accept event without PoW when min_difficulty=0
        }
    }

    // Perform PoW validation using nostr_core_lib
    nostr_pow_result_t pow_result;
    int validation_result = nostr_validate_pow(event, min_pow_difficulty,
                                             validation_flags, &pow_result);

    if (validation_result != NOSTR_SUCCESS) {
        // Handle specific error cases with appropriate messages
        switch (validation_result) {
            case NOSTR_ERROR_NIP13_INSUFFICIENT:
                snprintf(error_message, error_size,
                        "pow: insufficient difficulty: %d < %d",
                        pow_result.actual_difficulty, min_pow_difficulty);
                log_warning("Event rejected: insufficient PoW difficulty");
                break;
            case NOSTR_ERROR_NIP13_NO_NONCE_TAG:
                // This should not happen with min_difficulty=0 after our check above
                if (min_pow_difficulty > 0) {
                    snprintf(error_message, error_size, "pow: missing required nonce tag");
                    log_warning("Event rejected: missing nonce tag");
                } else {
                    return 0; // Allow when min_difficulty=0
                }
                break;
            case NOSTR_ERROR_NIP13_INVALID_NONCE_TAG:
                snprintf(error_message, error_size, "pow: invalid nonce tag format");
                log_warning("Event rejected: invalid nonce tag format");
                break;
            case NOSTR_ERROR_NIP13_TARGET_MISMATCH:
                snprintf(error_message, error_size,
                        "pow: committed target (%d) lower than minimum (%d)",
                        pow_result.committed_target, min_pow_difficulty);
                log_warning("Event rejected: committed target too low (anti-spam protection)");
                break;
            case NOSTR_ERROR_NIP13_CALCULATION:
                snprintf(error_message, error_size, "pow: difficulty calculation failed");
                log_error("PoW difficulty calculation error");
                break;
            case NOSTR_ERROR_EVENT_INVALID_ID:
                snprintf(error_message, error_size, "pow: invalid event ID format");
                log_warning("Event rejected: invalid event ID for PoW calculation");
                break;
            default:
                snprintf(error_message, error_size, "pow: validation failed - %s",
                        strlen(pow_result.error_detail) > 0 ? pow_result.error_detail : "unknown error");
                log_warning("Event rejected: PoW validation failed");
        }
        return validation_result;
    }

    return 0;  // Success
}