// Admin event handler for Kind 23458/23459 admin commands
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include "ginxsom.h"
#include "admin_commands.h"

// Forward declarations for nostr_core_lib functions
int nostr_hex_to_bytes(const char* hex, unsigned char* bytes, size_t bytes_len);
int nostr_nip44_decrypt(const unsigned char* recipient_private_key,
                       const unsigned char* sender_public_key,
                       const char* encrypted_data,
                       char* output,
                       size_t output_size);
int nostr_nip44_encrypt(const unsigned char* sender_private_key,
                       const unsigned char* recipient_public_key,
                       const char* plaintext,
                       char* output,
                       size_t output_size);
cJSON* nostr_create_and_sign_event(int kind, const char* content, cJSON* tags,
                                   const unsigned char* private_key, time_t created_at);

// Use global database path from main.c
extern char g_db_path[];

// Forward declarations
static int get_server_privkey(unsigned char* privkey_bytes);
static int get_server_pubkey(char* pubkey_hex, size_t size);
static int send_admin_response_event(const char* admin_pubkey, const char* request_id,
                                      cJSON* response_data);
static cJSON* parse_authorization_header(void);
static int process_admin_event(cJSON* event);

/**
 * Handle Kind 23458 admin command event
 * Supports two delivery methods:
 * 1. POST body with JSON event
 * 2. Authorization header with Nostr event
 */
void handle_admin_event_request(void) {
    cJSON* event = NULL;
    int should_free_event = 1;

    // First, try to get event from Authorization header
    event = parse_authorization_header();
    
    // If not in header, try POST body
    if (!event) {
        const char* content_length_str = getenv("CONTENT_LENGTH");
        if (!content_length_str) {
            printf("Status: 400 Bad Request\r\n");
            printf("Content-Type: application/json\r\n\r\n");
            printf("{\"error\":\"Event required in POST body or Authorization header\"}\n");
            return;
        }

        long content_length = atol(content_length_str);
        if (content_length <= 0 || content_length > 65536) {
            printf("Status: 400 Bad Request\r\n");
            printf("Content-Type: application/json\r\n\r\n");
            printf("{\"error\":\"Invalid content length\"}\n");
            return;
        }

        char* json_body = malloc(content_length + 1);
        if (!json_body) {
            printf("Status: 500 Internal Server Error\r\n");
            printf("Content-Type: application/json\r\n\r\n");
            printf("{\"error\":\"Memory allocation failed\"}\n");
            return;
        }

        size_t bytes_read = fread(json_body, 1, content_length, stdin);
        if (bytes_read != (size_t)content_length) {
            free(json_body);
            printf("Status: 400 Bad Request\r\n");
            printf("Content-Type: application/json\r\n\r\n");
            printf("{\"error\":\"Failed to read complete request body\"}\n");
            return;
        }
        json_body[content_length] = '\0';

        // Parse event JSON
        event = cJSON_Parse(json_body);
        
        // Debug: Log the received JSON
        app_log(LOG_DEBUG, "ADMIN_EVENT: Received POST body: %s", json_body);
        
        free(json_body);
        
        if (!event) {
            app_log(LOG_ERROR, "ADMIN_EVENT: Failed to parse JSON");
            printf("Status: 400 Bad Request\r\n");
            printf("Content-Type: application/json\r\n\r\n");
            printf("{\"error\":\"Invalid JSON\"}\n");
            return;
        }
        
        // Debug: Log parsed event
        char* event_str = cJSON_Print(event);
        if (event_str) {
            app_log(LOG_DEBUG, "ADMIN_EVENT: Parsed event: %s", event_str);
            free(event_str);
        }
    }

    // Process the event (handles validation, decryption, command execution, response)
    int result = process_admin_event(event);
    
    // Clean up
    if (should_free_event && event) {
        cJSON_Delete(event);
    }
    
    (void)result; // Result already handled by process_admin_event
}

/**
 * Parse Kind 23458 event from Authorization header
 * Format: Authorization: Nostr <base64-encoded-event-json>
 * Returns: cJSON event object or NULL if not present/invalid
 */
static cJSON* parse_authorization_header(void) {
    const char* auth_header = getenv("HTTP_AUTHORIZATION");
    if (!auth_header) {
        return NULL;
    }

    // Check for "Nostr " prefix (case-insensitive)
    if (strncasecmp(auth_header, "Nostr ", 6) != 0) {
        return NULL;
    }

    // Skip "Nostr " prefix
    const char* base64_event = auth_header + 6;
    
    // Decode base64 (simple implementation - in production use proper base64 decoder)
    // For now, assume the event is JSON directly (not base64 encoded)
    // This matches the pattern from c-relay's admin interface
    cJSON* event = cJSON_Parse(base64_event);
    
    return event;
}

/**
 * Process a Kind 23458 admin event (from POST body or Authorization header)
 * Returns: 0 on success, -1 on error (error response already sent)
 */
static int process_admin_event(cJSON* event) {
    if (!event) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Invalid event\"}\n");
        return -1;
    }

    // Verify it's Kind 23458
    cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
    if (!kind_obj || !cJSON_IsNumber(kind_obj) ||
        (int)cJSON_GetNumberValue(kind_obj) != 23458) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Event must be Kind 23458\"}\n");
        return -1;
    }

    // Get event ID for response correlation
    cJSON* id_obj = cJSON_GetObjectItem(event, "id");
    if (!id_obj || !cJSON_IsString(id_obj)) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Event missing id\"}\n");
        return -1;
    }
    const char* request_id = cJSON_GetStringValue(id_obj);

    // Get admin pubkey from event
    cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
    if (!pubkey_obj || !cJSON_IsString(pubkey_obj)) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Event missing pubkey\"}\n");
        return -1;
    }
    const char* admin_pubkey = cJSON_GetStringValue(pubkey_obj);

    // Verify admin pubkey
    sqlite3* db;
    int rc = sqlite3_open_v2(g_db_path, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc != SQLITE_OK) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Database error\"}\n");
        return -1;
    }

    sqlite3_stmt* stmt;
    const char* sql = "SELECT value FROM config WHERE key = 'admin_pubkey'";
    int is_admin = 0;
    
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            const char* db_admin_pubkey = (const char*)sqlite3_column_text(stmt, 0);
            if (db_admin_pubkey && strcmp(admin_pubkey, db_admin_pubkey) == 0) {
                is_admin = 1;
            }
        }
        sqlite3_finalize(stmt);
    }
    sqlite3_close(db);

    if (!is_admin) {
        printf("Status: 403 Forbidden\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Not authorized as admin\"}\n");
        return -1;
    }

    // Get encrypted content
    cJSON* content_obj = cJSON_GetObjectItem(event, "content");
    if (!content_obj || !cJSON_IsString(content_obj)) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Event missing content\"}\n");
        return -1;
    }
    const char* encrypted_content = cJSON_GetStringValue(content_obj);

    // Get server private key for decryption
    unsigned char server_privkey[32];
    if (get_server_privkey(server_privkey) != 0) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Failed to get server private key\"}\n");
        return -1;
    }

    // Convert admin pubkey to bytes
    unsigned char admin_pubkey_bytes[32];
    if (nostr_hex_to_bytes(admin_pubkey, admin_pubkey_bytes, 32) != 0) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Invalid admin pubkey format\"}\n");
        return -1;
    }

    // Decrypt content using NIP-44 (or use plaintext for testing)
    char decrypted_content[8192];
    const char* content_to_parse = encrypted_content;
    
    // Check if content is already plaintext JSON (starts with '[')
    if (encrypted_content[0] != '[') {
        // Content is encrypted, decrypt it
        int decrypt_result = nostr_nip44_decrypt(
            server_privkey,
            admin_pubkey_bytes,
            encrypted_content,
            decrypted_content,
            sizeof(decrypted_content)
        );

        if (decrypt_result != 0) {
            app_log(LOG_ERROR, "ADMIN_EVENT: Decryption failed with result: %d", decrypt_result);
            app_log(LOG_ERROR, "ADMIN_EVENT: Encrypted content: %s", encrypted_content);
            printf("Status: 400 Bad Request\r\n");
            printf("Content-Type: application/json\r\n\r\n");
            printf("{\"error\":\"Failed to decrypt content\"}\n");
            return -1;
        }
        content_to_parse = decrypted_content;
        app_log(LOG_DEBUG, "ADMIN_EVENT: Decrypted content: %s", decrypted_content);
    } else {
        app_log(LOG_DEBUG, "ADMIN_EVENT: Using plaintext content (starts with '['): %s", encrypted_content);
    }

    // Parse command array (either decrypted or plaintext)
    app_log(LOG_DEBUG, "ADMIN_EVENT: Parsing command array from: %s", content_to_parse);
    cJSON* command_array = cJSON_Parse(content_to_parse);
    if (!command_array || !cJSON_IsArray(command_array)) {
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Decrypted content is not a valid command array\"}\n");
        return -1;
    }

    // Get command type
    cJSON* command_type = cJSON_GetArrayItem(command_array, 0);
    if (!command_type || !cJSON_IsString(command_type)) {
        cJSON_Delete(command_array);
        printf("Status: 400 Bad Request\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Invalid command format\"}\n");
        return -1;
    }

    const char* cmd = cJSON_GetStringValue(command_type);
    
    // Create response data object
    cJSON* response_data = cJSON_CreateObject();
    cJSON_AddStringToObject(response_data, "query_type", cmd);
    cJSON_AddNumberToObject(response_data, "timestamp", (double)time(NULL));

    // Handle command - use admin_commands system for processing
    cJSON* command_response = admin_commands_process(command_array, request_id);
    
    int result = -1;
    if (command_response) {
        // Check if command was successful
        cJSON* status = cJSON_GetObjectItem(command_response, "status");
        if (status && cJSON_IsString(status)) {
            const char* status_str = cJSON_GetStringValue(status);
            if (strcmp(status_str, "success") == 0) {
                result = 0;
            }
        }
        
        // Copy response data from command_response to response_data
        cJSON* item = NULL;
        cJSON_ArrayForEach(item, command_response) {
            if (item->string) {
                cJSON* copy = cJSON_Duplicate(item, 1);
                cJSON_AddItemToObject(response_data, item->string, copy);
            }
        }
        
        cJSON_Delete(command_response);
        app_log(LOG_DEBUG, "ADMIN_EVENT: Command processed with result: %d", result);
    } else {
        app_log(LOG_ERROR, "ADMIN_EVENT: Command processing returned NULL");
        cJSON_AddStringToObject(response_data, "status", "error");
        cJSON_AddStringToObject(response_data, "error", "Command processing failed");
        result = -1;
    }

    cJSON_Delete(command_array);

    if (result == 0) {
        app_log(LOG_DEBUG, "ADMIN_EVENT: Sending Kind 23459 response");
        // Send Kind 23459 response
        int send_result = send_admin_response_event(admin_pubkey, request_id, response_data);
        app_log(LOG_DEBUG, "ADMIN_EVENT: Response sent with result: %d", send_result);
        return send_result;
    } else {
        app_log(LOG_ERROR, "ADMIN_EVENT: Command processing failed");
        cJSON_Delete(response_data);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Command processing failed\"}\n");
        return -1;
    }
}

/**
 * Get server private key from database (stored in blossom_seckey table)
 */
static int get_server_privkey(unsigned char* privkey_bytes) {
    sqlite3* db;
    int rc = sqlite3_open_v2(g_db_path, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc != SQLITE_OK) {
        return -1;
    }

    sqlite3_stmt* stmt;
    const char* sql = "SELECT seckey FROM blossom_seckey LIMIT 1";
    int result = -1;
    
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            const char* privkey_hex = (const char*)sqlite3_column_text(stmt, 0);
            if (privkey_hex && nostr_hex_to_bytes(privkey_hex, privkey_bytes, 32) == 0) {
                result = 0;
            }
        }
        sqlite3_finalize(stmt);
    }
    sqlite3_close(db);
    
    return result;
}

/**
 * Get server public key from database (stored in config table as blossom_pubkey)
 */
static int get_server_pubkey(char* pubkey_hex, size_t size) {
    sqlite3* db;
    int rc = sqlite3_open_v2(g_db_path, &db, SQLITE_OPEN_READONLY, NULL);
    if (rc != SQLITE_OK) {
        return -1;
    }

    sqlite3_stmt* stmt;
    const char* sql = "SELECT value FROM config WHERE key = 'blossom_pubkey'";
    int result = -1;
    
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            const char* pubkey = (const char*)sqlite3_column_text(stmt, 0);
            if (pubkey) {
                strncpy(pubkey_hex, pubkey, size - 1);
                pubkey_hex[size - 1] = '\0';
                result = 0;
            }
        }
        sqlite3_finalize(stmt);
    }
    sqlite3_close(db);
    
    return result;
}


/**
 * Send Kind 23459 admin response event
 */
static int send_admin_response_event(const char* admin_pubkey, const char* request_id,
                                     cJSON* response_data) {
    // Get server keys
    unsigned char server_privkey[32];
    char server_pubkey[65];
    
    if (get_server_privkey(server_privkey) != 0 || 
        get_server_pubkey(server_pubkey, sizeof(server_pubkey)) != 0) {
        cJSON_Delete(response_data);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Failed to get server keys\"}\n");
        return -1;
    }

    // Convert response data to JSON string
    char* response_json = cJSON_PrintUnformatted(response_data);
    cJSON_Delete(response_data);
    
    if (!response_json) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Failed to serialize response\"}\n");
        return -1;
    }

    // Convert admin pubkey to bytes for encryption
    unsigned char admin_pubkey_bytes[32];
    if (nostr_hex_to_bytes(admin_pubkey, admin_pubkey_bytes, 32) != 0) {
        free(response_json);
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Invalid admin pubkey\"}\n");
        return -1;
    }

    // Encrypt response using NIP-44
    char encrypted_response[131072];
    int encrypt_result = nostr_nip44_encrypt(
        server_privkey,
        admin_pubkey_bytes,
        response_json,
        encrypted_response,
        sizeof(encrypted_response)
    );
    
    free(response_json);
    
    if (encrypt_result != 0) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Failed to encrypt response\"}\n");
        return -1;
    }

    // Create Kind 23459 response event
    cJSON* response_event = cJSON_CreateObject();
    cJSON_AddStringToObject(response_event, "pubkey", server_pubkey);
    cJSON_AddNumberToObject(response_event, "created_at", (double)time(NULL));
    cJSON_AddNumberToObject(response_event, "kind", 23459);
    cJSON_AddStringToObject(response_event, "content", encrypted_response);
    
    // Add tags
    cJSON* tags = cJSON_CreateArray();
    
    // p tag for admin
    cJSON* p_tag = cJSON_CreateArray();
    cJSON_AddItemToArray(p_tag, cJSON_CreateString("p"));
    cJSON_AddItemToArray(p_tag, cJSON_CreateString(admin_pubkey));
    cJSON_AddItemToArray(tags, p_tag);
    
    // e tag for request correlation
    cJSON* e_tag = cJSON_CreateArray();
    cJSON_AddItemToArray(e_tag, cJSON_CreateString("e"));
    cJSON_AddItemToArray(e_tag, cJSON_CreateString(request_id));
    cJSON_AddItemToArray(tags, e_tag);
    
    cJSON_AddItemToObject(response_event, "tags", tags);

    // Sign the event
    cJSON* signed_event = nostr_create_and_sign_event(
        23459,
        encrypted_response,
        tags,
        server_privkey,
        time(NULL)
    );
    
    cJSON_Delete(response_event);
    
    if (!signed_event) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Failed to sign response event\"}\n");
        return -1;
    }

    // Return the signed event as HTTP response
    char* event_json = cJSON_PrintUnformatted(signed_event);
    cJSON_Delete(signed_event);
    
    if (!event_json) {
        printf("Status: 500 Internal Server Error\r\n");
        printf("Content-Type: application/json\r\n\r\n");
        printf("{\"error\":\"Failed to serialize event\"}\n");
        return -1;
    }

    printf("Status: 200 OK\r\n");
    printf("Content-Type: application/json\r\n");
    printf("Cache-Control: no-cache\r\n");
    printf("\r\n");
    printf("%s\n", event_json);
    
    free(event_json);
    return 0;
}