#define _GNU_SOURCE

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//             NIP-09 EVENT DELETION REQUEST HANDLING
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
#include <cjson/cJSON.h>
#include "debug.h"
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>


// Forward declaration for database functions
int store_event(cJSON* event);

// Forward declarations for deletion functions
int delete_events_by_id(const char* requester_pubkey, cJSON* event_ids);
int delete_events_by_address(const char* requester_pubkey, cJSON* addresses, long deletion_timestamp);

// Global database variable
extern sqlite3* g_db;


// Handle NIP-09 deletion request event (kind 5)
int handle_deletion_request(cJSON* event, char* error_message, size_t error_size) {
    if (!event) {
        snprintf(error_message, error_size, "invalid: null deletion request");
        return -1;
    }
    
    // Extract event details
    cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
    cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
    cJSON* created_at_obj = cJSON_GetObjectItem(event, "created_at");
    cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
    cJSON* content_obj = cJSON_GetObjectItem(event, "content");
    cJSON* event_id_obj = cJSON_GetObjectItem(event, "id");
    
    if (!kind_obj || !pubkey_obj || !created_at_obj || !tags_obj || !event_id_obj) {
        snprintf(error_message, error_size, "invalid: incomplete deletion request");
        return -1;
    }
    
    int kind = (int)cJSON_GetNumberValue(kind_obj);
    if (kind != 5) {
        snprintf(error_message, error_size, "invalid: not a deletion request");
        return -1;
    }
    
    const char* requester_pubkey = cJSON_GetStringValue(pubkey_obj);
    // Extract deletion event ID and reason (for potential logging)
    const char* deletion_event_id = cJSON_GetStringValue(event_id_obj);
    const char* reason = content_obj ? cJSON_GetStringValue(content_obj) : "";
    (void)deletion_event_id; // Mark as intentionally unused for now
    (void)reason;           // Mark as intentionally unused for now
    long deletion_timestamp = (long)cJSON_GetNumberValue(created_at_obj);
    
    if (!cJSON_IsArray(tags_obj)) {
        snprintf(error_message, error_size, "invalid: deletion request tags must be an array");
        return -1;
    }
    
    // Collect event IDs and addresses from tags
    cJSON* event_ids = cJSON_CreateArray();
    cJSON* addresses = cJSON_CreateArray();
    cJSON* kinds_to_delete = cJSON_CreateArray();
    
    int deletion_targets_found = 0;
    
    cJSON* tag = NULL;
    cJSON_ArrayForEach(tag, tags_obj) {
        if (!cJSON_IsArray(tag) || cJSON_GetArraySize(tag) < 2) {
            continue;
        }
        
        cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
        cJSON* tag_value = cJSON_GetArrayItem(tag, 1);
        
        if (!cJSON_IsString(tag_name) || !cJSON_IsString(tag_value)) {
            continue;
        }
        
        const char* name = cJSON_GetStringValue(tag_name);
        const char* value = cJSON_GetStringValue(tag_value);
        
        if (strcmp(name, "e") == 0) {
            // Event ID reference
            cJSON_AddItemToArray(event_ids, cJSON_CreateString(value));
            deletion_targets_found++;
        } else if (strcmp(name, "a") == 0) {
            // Addressable event reference (kind:pubkey:d-identifier)
            cJSON_AddItemToArray(addresses, cJSON_CreateString(value));
            deletion_targets_found++;
        } else if (strcmp(name, "k") == 0) {
            // Kind hint - store for validation but not required
            int kind_hint = atoi(value);
            if (kind_hint > 0) {
                cJSON_AddItemToArray(kinds_to_delete, cJSON_CreateNumber(kind_hint));
            }
        }
    }
    
    if (deletion_targets_found == 0) {
        cJSON_Delete(event_ids);
        cJSON_Delete(addresses);
        cJSON_Delete(kinds_to_delete);
        snprintf(error_message, error_size, "invalid: deletion request must contain 'e' or 'a' tags");
        return -1;
    }
    
    int deleted_count = 0;
    
    // Process event ID deletions
    if (cJSON_GetArraySize(event_ids) > 0) {
        int result = delete_events_by_id(requester_pubkey, event_ids);
        if (result > 0) {
            deleted_count += result;
        }
    }
    
    // Process addressable event deletions
    if (cJSON_GetArraySize(addresses) > 0) {
        int result = delete_events_by_address(requester_pubkey, addresses, deletion_timestamp);
        if (result > 0) {
            deleted_count += result;
        }
    }
    
    // Clean up
    cJSON_Delete(event_ids);
    cJSON_Delete(addresses);
    cJSON_Delete(kinds_to_delete);
    
    // Store the deletion request itself (it should be kept according to NIP-09)
    if (store_event(event) != 0) {
        DEBUG_WARN("Failed to store deletion request event");
    }

    error_message[0] = '\0'; // Success - empty error message
    return 0;
}

// Delete events by ID (with pubkey authorization)
int delete_events_by_id(const char* requester_pubkey, cJSON* event_ids) {
    if (!g_db || !requester_pubkey || !event_ids || !cJSON_IsArray(event_ids)) {
        return 0;
    }
    
    int deleted_count = 0;
    
    cJSON* event_id = NULL;
    cJSON_ArrayForEach(event_id, event_ids) {
        if (!cJSON_IsString(event_id)) {
            continue;
        }
        
        const char* id = cJSON_GetStringValue(event_id);
        
        // First check if event exists and if requester is authorized
        const char* check_sql = "SELECT pubkey FROM events WHERE id = ?";
        sqlite3_stmt* check_stmt;
        
        int rc = sqlite3_prepare_v2(g_db, check_sql, -1, &check_stmt, NULL);
        if (rc != SQLITE_OK) {
            continue;
        }
        
        sqlite3_bind_text(check_stmt, 1, id, -1, SQLITE_STATIC);
        
        if (sqlite3_step(check_stmt) == SQLITE_ROW) {
            const char* event_pubkey = (char*)sqlite3_column_text(check_stmt, 0);
            
            // Only delete if the requester is the author
            if (event_pubkey && strcmp(event_pubkey, requester_pubkey) == 0) {
                sqlite3_finalize(check_stmt);
                
                // Delete the event
                const char* delete_sql = "DELETE FROM events WHERE id = ? AND pubkey = ?";
                sqlite3_stmt* delete_stmt;
                
                rc = sqlite3_prepare_v2(g_db, delete_sql, -1, &delete_stmt, NULL);
                if (rc == SQLITE_OK) {
                    sqlite3_bind_text(delete_stmt, 1, id, -1, SQLITE_STATIC);
                    sqlite3_bind_text(delete_stmt, 2, requester_pubkey, -1, SQLITE_STATIC);
                    
                    if (sqlite3_step(delete_stmt) == SQLITE_DONE && sqlite3_changes(g_db) > 0) {
                        deleted_count++;
                    }
                    sqlite3_finalize(delete_stmt);
                }
            } else {
                sqlite3_finalize(check_stmt);
                char warning_msg[128];
                snprintf(warning_msg, sizeof(warning_msg), "Unauthorized deletion attempt for event: %.16s...", id);
                DEBUG_WARN(warning_msg);
            }
        } else {
            sqlite3_finalize(check_stmt);
        }
    }
    
    return deleted_count;
}

// Delete events by addressable reference (kind:pubkey:d-identifier)
int delete_events_by_address(const char* requester_pubkey, cJSON* addresses, long deletion_timestamp) {
    if (!g_db || !requester_pubkey || !addresses || !cJSON_IsArray(addresses)) {
        return 0;
    }
    
    int deleted_count = 0;
    
    cJSON* address = NULL;
    cJSON_ArrayForEach(address, addresses) {
        if (!cJSON_IsString(address)) {
            continue;
        }
        
        const char* addr = cJSON_GetStringValue(address);
        
        // Parse address format: kind:pubkey:d-identifier
        char* addr_copy = strdup(addr);
        if (!addr_copy) continue;
        
        char* kind_str = strtok(addr_copy, ":");
        char* pubkey_str = strtok(NULL, ":");
        char* d_identifier = strtok(NULL, ":");
        
        if (!kind_str || !pubkey_str) {
            free(addr_copy);
            continue;
        }
        
        int kind = atoi(kind_str);
        
        // Only delete if the requester is the author
        if (strcmp(pubkey_str, requester_pubkey) != 0) {
            free(addr_copy);
            char warning_msg[128];
            snprintf(warning_msg, sizeof(warning_msg), "Unauthorized deletion attempt for address: %.32s...", addr);
            DEBUG_WARN(warning_msg);
            continue;
        }
        
        // Build deletion query based on whether we have d-identifier
        const char* delete_sql;
        sqlite3_stmt* delete_stmt;
        
        if (d_identifier && strlen(d_identifier) > 0) {
            // Delete specific addressable event with d-tag
            delete_sql = "DELETE FROM events WHERE kind = ? AND pubkey = ? AND created_at <= ? "
                        "AND json_extract(tags, '$[*]') LIKE '%[\"d\",\"' || ? || '\"]%'";
        } else {
            // Delete all events of this kind by this author up to deletion timestamp
            delete_sql = "DELETE FROM events WHERE kind = ? AND pubkey = ? AND created_at <= ?";
        }
        
        int rc = sqlite3_prepare_v2(g_db, delete_sql, -1, &delete_stmt, NULL);
        if (rc == SQLITE_OK) {
            sqlite3_bind_int(delete_stmt, 1, kind);
            sqlite3_bind_text(delete_stmt, 2, requester_pubkey, -1, SQLITE_STATIC);
            sqlite3_bind_int64(delete_stmt, 3, deletion_timestamp);
            
            if (d_identifier && strlen(d_identifier) > 0) {
                sqlite3_bind_text(delete_stmt, 4, d_identifier, -1, SQLITE_STATIC);
            }
            
            if (sqlite3_step(delete_stmt) == SQLITE_DONE) {
                int changes = sqlite3_changes(g_db);
                if (changes > 0) {
                    deleted_count += changes;
                }
            }
            sqlite3_finalize(delete_stmt);
        }
        
        free(addr_copy);
    }
    
    return deleted_count;
}

// Mark event as deleted (alternative to hard deletion - not used in current implementation)
int mark_event_as_deleted(const char* event_id, const char* deletion_event_id, const char* reason) {
    (void)event_id; (void)deletion_event_id; (void)reason; // Suppress unused warnings
    
    // This function could be used if we wanted to implement soft deletion
    // For now, NIP-09 implementation uses hard deletion as specified
    
    return 0;
}
