// Global error handler to prevent page refreshes
window.addEventListener('error', function (e) {
    console.error('Global error caught:', e.error);
    console.error('Error message:', e.message);
    console.error('Error filename:', e.filename);
    console.error('Error line:', e.lineno);
    e.preventDefault(); // Prevent default browser error handling
    return true; // Prevent page refresh
});

window.addEventListener('unhandledrejection', function (e) {
    console.error('Unhandled promise rejection:', e.reason);
    e.preventDefault(); // Prevent default browser error handling
    return true; // Prevent page refresh
});

// Global state
let nlLite = null;
let userPubkey = null;
let isLoggedIn = false;
let currentConfig = null;
// Global subscription state
let relayPool = null;
let subscriptionId = null;
let isSubscribed = false; // Flag to prevent multiple simultaneous subscriptions
let isSubscribing = false; // Flag to prevent re-entry during subscription setup
// Relay connection state
let relayInfo = null;
let isRelayConnected = false;
let relayPubkey = null;
// Simple relay URL object (replaces DOM element)
let relayConnectionUrl = { value: '' };
// Database statistics auto-refresh
let statsAutoRefreshInterval = null;
let countdownInterval = null;
let countdownSeconds = 10;

// Side navigation state
let currentPage = 'statistics'; // Default page
let sideNavOpen = false;

// SQL Query state
let pendingSqlQueries = new Map();

// Real-time event rate chart
let eventRateChart = null;
let previousTotalEvents = 0; // Track previous total for rate calculation

// Relay Events state - now handled by main subscription

// DOM elements
const loginModal = document.getElementById('login-modal');
const loginModalContainer = document.getElementById('login-modal-container');
const profileArea = document.getElementById('profile-area');
const headerUserImage = document.getElementById('header-user-image');
const headerUserName = document.getElementById('header-user-name');

// Legacy elements (kept for backward compatibility)
const persistentUserName = document.getElementById('persistent-user-name');
const persistentUserPubkey = document.getElementById('persistent-user-pubkey');
const persistentUserAbout = document.getElementById('persistent-user-about');
const persistentUserDetails = document.getElementById('persistent-user-details');
const fetchConfigBtn = document.getElementById('fetch-config-btn');
const configDisplay = document.getElementById('config-display');
const configTableBody = document.getElementById('config-table-body');

// NIP-17 DM elements
const dmOutbox = document.getElementById('dm-outbox');
const dmInbox = document.getElementById('dm-inbox');
const sendDmBtn = document.getElementById('send-dm-btn');

// Utility functions
function log(message, type = 'INFO') {
    const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
    const logMessage = `${timestamp} [${type}]: ${message}`;

    // Always log to browser console so we don't lose logs on refresh
    console.log(logMessage);

    // UI logging removed - using console only
}

// Utility functions
function log(message, type = 'INFO') {
    const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
    const logMessage = `${timestamp} [${type}]: ${message}`;

    // Always log to browser console so we don't lose logs on refresh
    console.log(logMessage);

    // UI logging removed - using console only
}


// NIP-59 helper: randomize created_at to thwart time-analysis (past 2 days)
// TEMPORARILY DISABLED: Using current timestamp for debugging
function randomNow() {
    // const TWO_DAYS = 2 * 24 * 60 * 60; // 172800 seconds
    const now = Math.round(Date.now() / 1000);
    return now; // Math.round(now - Math.random() * TWO_DAYS);
}

// Safe JSON parse with error handling
function safeJsonParse(jsonString) {
    try {
        return JSON.parse(jsonString);
    } catch (error) {
        console.error('JSON parse error:', error);
        return null;
    }
}
// ================================
// NIP-11 RELAY CONNECTION FUNCTIONS
// ================================

// Convert WebSocket URL to HTTP URL for NIP-11
function wsToHttpUrl(wsUrl) {
    if (wsUrl.startsWith('ws://')) {
        return wsUrl.replace('ws://', 'http://');
    } else if (wsUrl.startsWith('wss://')) {
        return wsUrl.replace('wss://', 'https://');
    }
    return wsUrl;
}

// Fetch relay information using NIP-11
async function fetchRelayInfo(relayUrl) {
    try {
        log(`Fetching NIP-11 relay info from: ${relayUrl}`, 'INFO');

        // Convert WebSocket URL to HTTP URL
        const httpUrl = wsToHttpUrl(relayUrl);

        // Make HTTP request with NIP-11 headers
        const response = await fetch(httpUrl, {
            method: 'GET',
            headers: {
                'Accept': 'application/nostr+json',
                'User-Agent': 'C-Relay-Admin-API/1.0'
            },
            timeout: 10000 // 10 second timeout
        });

        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }

        const contentType = response.headers.get('content-type');
        if (!contentType || !contentType.includes('application/nostr+json')) {
            throw new Error(`Invalid content type: ${contentType}. Expected application/nostr+json`);
        }

        const relayInfo = await response.json();

        // Log if relay info is empty (not configured yet) but don't throw error
        if (!relayInfo || Object.keys(relayInfo).length === 0) {
            log('Relay returned empty NIP-11 info - relay not configured yet, will use manual pubkey if provided', 'INFO');
            // Return empty object - this is valid, caller will handle manual pubkey fallback
            return {};
        }

        // Validate pubkey if present
        if (relayInfo.pubkey && !/^[0-9a-fA-F]{64}$/.test(relayInfo.pubkey)) {
            throw new Error(`Invalid relay pubkey format: ${relayInfo.pubkey}`);
        }

        log(`Successfully fetched relay info. Pubkey: ${relayInfo.pubkey ? relayInfo.pubkey.substring(0, 16) + '...' : 'not set'}`, 'INFO');
        return relayInfo;

    } catch (error) {
        log(`Failed to fetch relay info: ${error.message}`, 'ERROR');
        throw error;
    }
}

// Test WebSocket connection to relay
async function testWebSocketConnection(wsUrl) {
    return new Promise((resolve, reject) => {
        try {
            log(`Testing WebSocket connection to: ${wsUrl}`, 'INFO');

            const ws = new WebSocket(wsUrl);
            const timeout = setTimeout(() => {
                ws.close();
                reject(new Error('WebSocket connection timeout (10s)'));
            }, 10000);

            ws.onopen = () => {
                clearTimeout(timeout);
                log('WebSocket connection successful', 'INFO');
                ws.close();
                resolve(true);
            };

            ws.onerror = (error) => {
                clearTimeout(timeout);
                log(`WebSocket connection failed: ${error.message || 'Unknown error'}`, 'ERROR');
                reject(new Error('WebSocket connection failed'));
            };

            ws.onclose = (event) => {
                if (event.code !== 1000) { // 1000 = normal closure
                    clearTimeout(timeout);
                    reject(new Error(`WebSocket closed unexpectedly: ${event.code} ${event.reason}`));
                }
            };

        } catch (error) {
            log(`WebSocket test error: ${error.message}`, 'ERROR');
            reject(error);
        }
    });
}





// Check for existing authentication state with multiple API methods and retry logic
async function checkExistingAuthWithRetries() {
    console.log('Starting authentication state detection with retry logic...');

    const maxAttempts = 3;
    const delay = 200; // ms between attempts (reduced from 500ms)

    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        console.log(`Authentication detection attempt ${attempt}/${maxAttempts}`);

        try {
            // Method 1: Try window.NOSTR_LOGIN_LITE.getAuthState()
            if (window.NOSTR_LOGIN_LITE && typeof window.NOSTR_LOGIN_LITE.getAuthState === 'function') {
                console.log('Trying window.NOSTR_LOGIN_LITE.getAuthState()...');
                const authState = window.NOSTR_LOGIN_LITE.getAuthState();
                if (authState && authState.pubkey) {
                    console.log('✅ Auth state found via NOSTR_LOGIN_LITE.getAuthState():', authState.pubkey);
                    await restoreAuthenticationState(authState.pubkey);
                    return true;
                }
            }

            // Method 2: Try nlLite.getPublicKey()
            if (nlLite && typeof nlLite.getPublicKey === 'function') {
                console.log('Trying nlLite.getPublicKey()...');
                const pubkey = await nlLite.getPublicKey();
                if (pubkey && pubkey.length === 64) {
                    console.log('✅ Pubkey found via nlLite.getPublicKey():', pubkey);
                    await restoreAuthenticationState(pubkey);
                    return true;
                }
            }

            // Method 3: Try window.nostr.getPublicKey() (NIP-07)
            if (window.nostr && typeof window.nostr.getPublicKey === 'function') {
                console.log('Trying window.nostr.getPublicKey()...');
                const pubkey = await window.nostr.getPublicKey();
                if (pubkey && pubkey.length === 64) {
                    console.log('✅ Pubkey found via window.nostr.getPublicKey():', pubkey);
                    await restoreAuthenticationState(pubkey);
                    return true;
                }
            }

            // Method 4: Check localStorage directly for NOSTR_LOGIN_LITE data
            const localStorageData = localStorage.getItem('NOSTR_LOGIN_LITE_DATA');
            if (localStorageData) {
                try {
                    const parsedData = JSON.parse(localStorageData);
                    if (parsedData.pubkey) {
                        console.log('✅ Pubkey found in localStorage:', parsedData.pubkey);
                        await restoreAuthenticationState(parsedData.pubkey);
                        return true;
                    }
                } catch (parseError) {
                    console.log('Failed to parse localStorage data:', parseError.message);
                }
            }

            console.log(`❌ Attempt ${attempt}: No authentication found via any method`);

            // Wait before next attempt (except for last attempt)
            if (attempt < maxAttempts) {
                await new Promise(resolve => setTimeout(resolve, delay));
            }

        } catch (error) {
            console.log(`❌ Attempt ${attempt} failed:`, error.message);
            if (attempt < maxAttempts) {
                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }
    }

    console.log('🔍 Authentication detection completed - no existing auth found after all attempts');
    return false;
}

// Helper function to restore authentication state
async function restoreAuthenticationState(pubkey) {
    console.log('🔄 Restoring authentication state for pubkey:', pubkey);

    userPubkey = pubkey;
    isLoggedIn = true;

    // Show main interface and profile in header
    showProfileInHeader();
    loadUserProfile();

    // Automatically set up relay connection (but don't show admin sections yet)
    await setupAutomaticRelayConnection();

    console.log('✅ Authentication state restored successfully');
}

// Automatically set up relay connection based on current page URL
async function setupAutomaticRelayConnection(showSections = false) {
    console.log('=== SETUP AUTOMATIC RELAY CONNECTION CALLED ===');
    console.log('Call stack:', new Error().stack);
    console.log('showSections:', showSections);
    console.log('Current isRelayConnected:', isRelayConnected);
    console.log('Current relayPool:', relayPool ? 'EXISTS' : 'NULL');
    console.log('Current isSubscribed:', isSubscribed);
    
    try {
        // Get the current page URL and convert to WebSocket URL
        const currentUrl = window.location.href;
        let relayUrl = '';

        if (currentUrl.startsWith('https://')) {
            relayUrl = currentUrl.replace('https://', 'wss://');
        } else if (currentUrl.startsWith('http://')) {
            relayUrl = currentUrl.replace('http://', 'ws://');
        } else {
            // Fallback for development
            relayUrl = 'ws://localhost:8888';
        }

        // Remove any path components to get just the base URL
        // CRITICAL: Always add trailing slash for consistent URL format
        const url = new URL(relayUrl);
        relayUrl = `${url.protocol}//${url.host}/`;

        // Set the relay URL
        relayConnectionUrl.value = relayUrl;

        console.log('🔗 Auto-setting relay URL to:', relayUrl);

        // Fetch relay info to get pubkey
        try {
            const httpUrl = relayUrl.replace('ws', 'http').replace('wss', 'https');
            const relayInfo = await fetchRelayInfo(httpUrl);

            if (relayInfo && relayInfo.pubkey) {
                relayPubkey = relayInfo.pubkey;
                console.log('🔑 Auto-fetched relay pubkey:', relayPubkey.substring(0, 16) + '...');
            } else {
                // Use fallback pubkey
                relayPubkey = '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa';
                console.log('⚠️ Using fallback relay pubkey');
            }
        } catch (error) {
            console.log('⚠️ Could not fetch relay info, using fallback pubkey:', error.message);
            relayPubkey = '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa';
        }

        // Set up subscription to receive admin API responses
        // Note: subscribeToConfiguration() will create the SimplePool internally
        await subscribeToConfiguration();
        console.log('📡 Subscription established for admin API responses');

        // Mark as connected
        isRelayConnected = true;

        // Update relay info in header
        updateRelayInfoInHeader();

        // Only show admin sections if explicitly requested
        if (showSections) {
            updateAdminSectionsVisibility();
        }

        console.log('✅ Automatic relay connection setup complete');

    } catch (error) {
        console.error('❌ Failed to setup automatic relay connection:', error);
        // Still mark as connected to allow basic functionality
        isRelayConnected = true;
        if (showSections) {
            updateAdminSectionsVisibility();
        }
    }
}

// Legacy function for backward compatibility
async function checkExistingAuth() {
    return await checkExistingAuthWithRetries();
}

// Initialize NOSTR_LOGIN_LITE
async function initializeApp() {
    try {
        await window.NOSTR_LOGIN_LITE.init({
            theme: 'default',
            methods: {
                extension: true,
                local: true,
                seedphrase: true,
                readonly: true,
                connect: true,
                remote: true,
                otp: false
            },
            floatingTab: {
                enabled: false
            }
        });

        nlLite = window.NOSTR_LOGIN_LITE;
        console.log('Nostr login system initialized');

        // Check for existing authentication state after initialization
        const wasAlreadyLoggedIn = await checkExistingAuth();
        if (wasAlreadyLoggedIn) {
            console.log('User was already logged in, showing profile in header');
            showProfileInHeader();
            // Show admin sections since user is already authenticated and relay is connected
            updateAdminSectionsVisibility();
        } else {
            console.log('No existing authentication found, showing login modal');
            showLoginModal();
        }

        // Listen for authentication events
        window.addEventListener('nlMethodSelected', handleAuthEvent);
        window.addEventListener('nlLogout', handleLogoutEvent);

    } catch (error) {
        console.log('Failed to initialize Nostr login: ' + error.message);
    }
}

// Handle authentication events
function handleAuthEvent(event) {
    const { pubkey, method, error } = event.detail;

    if (method && pubkey) {
        userPubkey = pubkey;
        isLoggedIn = true;
        console.log(`Login successful! Method: ${method}`);
        console.log(`Public key: ${pubkey}`);

        // Hide login modal and show profile in header
        hideLoginModal();
        showProfileInHeader();
        loadUserProfile();

        // Automatically set up relay connection and show admin sections
        setupAutomaticRelayConnection(true);

        // Auto-enable monitoring when admin logs in
        autoEnableMonitoring();

    } else if (error) {
        console.log(`Authentication error: ${error}`);
    }
}

// Handle logout events
function handleLogoutEvent() {
    console.log('Logout event received');

    userPubkey = null;
    isLoggedIn = false;
    currentConfig = null;

    // Reset relay connection state
    isRelayConnected = false;
    relayPubkey = null;

    // Reset UI - hide profile and show login modal
    hideProfileFromHeader();
    showLoginModal();

    updateConfigStatus(false);
    updateAdminSectionsVisibility();

    console.log('Logout event handled successfully');
}


// Update visibility of admin sections based on login and relay connection status
function updateAdminSectionsVisibility() {
    const shouldShow = isLoggedIn && isRelayConnected;

    // If logged in and connected, show the current page, otherwise hide all sections
    if (shouldShow) {
        // Show the current page
        switchPage(currentPage);

        // Load data for the current page
        loadCurrentPageData();
    } else {
        // Hide all sections when not logged in or not connected
        const sections = [
            'databaseStatisticsSection',
            'subscriptionDetailsSection',
            'div_config',
            'authRulesSection',
            'nip17DMSection',
            'sqlQuerySection'
        ];

        sections.forEach(sectionId => {
            const section = document.getElementById(sectionId);
            if (section) {
                section.style.display = 'none';
            }
        });

        stopStatsAutoRefresh();
    }

    // Update countdown display when visibility changes
    updateCountdownDisplay();
}

// Load data for the current page
function loadCurrentPageData() {
    switch (currentPage) {
        case 'statistics':
            // Load statistics immediately (no auto-refresh - using real-time monitoring events)
            sendStatsQuery().catch(error => {
                console.log('Auto-fetch statistics failed: ' + error.message);
            });
            break;
        case 'configuration':
            // Load configuration
            fetchConfiguration().catch(error => {
                console.log('Auto-fetch configuration failed: ' + error.message);
            });
            break;
        case 'authorization':
            // Load auth rules
            loadAuthRules().catch(error => {
                console.log('Auto-load auth rules failed: ' + error.message);
            });
            break;
        // Other pages don't need initial data loading
    }
}

// Show login modal
function showLoginModal() {
    if (loginModal && loginModalContainer) {
        // Initialize the login UI in the modal
        if (window.NOSTR_LOGIN_LITE && typeof window.NOSTR_LOGIN_LITE.embed === 'function') {
            window.NOSTR_LOGIN_LITE.embed('#login-modal-container', {
                seamless: true
            });
        }
        loginModal.style.display = 'flex';
    }
}

// Hide login modal
function hideLoginModal() {
    if (loginModal) {
        loginModal.style.display = 'none';
    }
}

// Show profile in header
function showProfileInHeader() {
    if (profileArea) {
        profileArea.style.display = 'flex';
    }
}

// Hide profile from header
function hideProfileFromHeader() {
    if (profileArea) {
        profileArea.style.display = 'none';
    }
}

// Update login/logout UI visibility (legacy function - kept for backward compatibility)
function updateLoginLogoutUI() {
    // This function is now handled by showProfileInHeader() and hideProfileFromHeader()
    // Kept for backward compatibility with any existing code that might call it
}

// Show main interface after login (legacy function - kept for backward compatibility)
function showMainInterface() {
    // This function is now handled by showProfileInHeader() and updateAdminSectionsVisibility()
    // Kept for backward compatibility with any existing code that might call it
    updateAdminSectionsVisibility();
}

// Load user profile using nostr-tools pool
async function loadUserProfile() {
    if (!userPubkey) return;

    console.log('Loading user profile...');

    // Update header display (new system)
    if (headerUserName) {
        headerUserName.textContent = 'Loading...';
    }

    // Update legacy elements if they exist (backward compatibility)
    if (persistentUserName) {
        persistentUserName.textContent = 'Loading...';
    }
    if (persistentUserAbout) {
        persistentUserAbout.textContent = 'Loading...';
    }

    // Convert hex pubkey to npub for initial display
    let displayPubkey = userPubkey;
    let npubLink = '';
    try {
        if (userPubkey && userPubkey.length === 64 && /^[0-9a-fA-F]+$/.test(userPubkey)) {
            const npub = window.NostrTools.nip19.npubEncode(userPubkey);
            displayPubkey = npub;
            npubLink = `<a href="https://njump.me/${npub}" target="_blank" class="npub-link">${npub}</a>`;
        }
    } catch (error) {
        console.log('Failed to encode user pubkey to npub:', error.message);
    }

    if (persistentUserPubkey) {
        if (npubLink) {
            persistentUserPubkey.innerHTML = npubLink;
        } else {
            persistentUserPubkey.textContent = displayPubkey;
        }
    }

    try {
        // Create a SimplePool instance for profile loading
        const profilePool = new window.NostrTools.SimplePool();
        const relays = ['wss://relay.damus.io',
            'wss://relay.nostr.band',
            'wss://nos.lol',
            'wss://relay.primal.net',
            'wss://relay.snort.social'
        ];

        // Get profile event (kind 0) for the user with timeout
        const timeoutPromise = new Promise((_, reject) =>
            setTimeout(() => reject(new Error('Profile query timeout')), 5000)
        );
        
        const queryPromise = profilePool.querySync(relays, {
            kinds: [0],
            authors: [userPubkey],
            limit: 1
        });

        const events = await Promise.race([queryPromise, timeoutPromise]);

        if (events.length > 0) {
            console.log('Profile event found:', events[0]);
            const profile = JSON.parse(events[0].content);
            console.log('Parsed profile:', profile);
            displayProfile(profile);
        } else {
            console.log('No profile events found for pubkey:', userPubkey);

            // Update header display (new system)
            if (headerUserName) {
                headerUserName.textContent = 'Anonymous User';
            }

            // Update legacy elements if they exist (backward compatibility)
            if (persistentUserName) {
                persistentUserName.textContent = 'Anonymous User';
            }
            if (persistentUserAbout) {
                persistentUserAbout.textContent = 'No profile found';
            }
            // Keep the npub display
        }

        // Properly close the profile pool with error handling
        try {
            await profilePool.close(relays);
            // Give time for cleanup
            await new Promise(resolve => setTimeout(resolve, 100));
        } catch (closeError) {
            console.log('Profile pool close error (non-critical):', closeError.message);
        }

    } catch (error) {
        console.log('Profile loading failed: ' + error.message);

        // Update header display (new system)
        if (headerUserName) {
            headerUserName.textContent = 'Error loading profile';
        }

        // Update legacy elements if they exist (backward compatibility)
        if (persistentUserName) {
            persistentUserName.textContent = 'Error loading profile';
        }
        if (persistentUserAbout) {
            persistentUserAbout.textContent = error.message;
        }
        // Keep the npub display
    }
}

// Display profile data
function displayProfile(profile) {
    const name = profile.name || profile.display_name || profile.displayName || 'Anonymous User';
    const about = profile.about || 'No description provided';
    const picture = profile.picture || profile.image || null;

    // Convert hex pubkey to npub for display
    let displayPubkey = userPubkey;
    let npubLink = '';
    try {
        if (userPubkey && userPubkey.length === 64 && /^[0-9a-fA-F]+$/.test(userPubkey)) {
            const npub = window.NostrTools.nip19.npubEncode(userPubkey);
            displayPubkey = npub;
            npubLink = `<a href="https://njump.me/${npub}" target="_blank" class="npub-link">${npub}</a>`;
        }
    } catch (error) {
        console.log('Failed to encode user pubkey to npub:', error.message);
    }

    // Update header profile display
    if (headerUserName) {
        headerUserName.textContent = name;
    }

    // Handle header profile picture
    if (headerUserImage) {
        if (picture && typeof picture === 'string' && (picture.startsWith('http') || picture.startsWith('https'))) {
            headerUserImage.src = picture;
            headerUserImage.style.display = 'block';
            headerUserImage.onerror = function() {
                // Hide image on error
                this.style.display = 'none';
                console.log('Profile image failed to load:', picture);
            };
        } else {
            headerUserImage.style.display = 'none';
        }
    }

    // Update legacy persistent user details (kept for backward compatibility)
    if (persistentUserName) persistentUserName.textContent = name;
    if (persistentUserPubkey && npubLink) {
        persistentUserPubkey.innerHTML = npubLink;
    } else if (persistentUserPubkey) {
        persistentUserPubkey.textContent = displayPubkey;
    }
    if (persistentUserAbout) persistentUserAbout.textContent = about;

    // Handle legacy profile picture
    const userImageContainer = document.getElementById('persistent-user-image');
    if (userImageContainer) {
        if (picture && typeof picture === 'string' && picture.startsWith('http')) {
            // Create or update image element
            let img = userImageContainer.querySelector('img');
            if (!img) {
                img = document.createElement('img');
                img.className = 'user-profile-image';
                img.alt = `${name}'s profile picture`;
                img.onerror = function() {
                    // Hide image on error
                    this.style.display = 'none';
                };
                userImageContainer.appendChild(img);
            }
            img.src = picture;
            img.style.display = 'block';
        } else {
            // Hide image if no valid picture
            const img = userImageContainer.querySelector('img');
            if (img) {
                img.style.display = 'none';
            }
        }
    }

    console.log(`Profile loaded for: ${name} with pubkey: ${userPubkey}`);
}

// Logout function
async function logout() {
    log('Logging out...', 'INFO');
    try {
        // Stop auto-refresh before disconnecting
        stopStatsAutoRefresh();

        // Clean up relay pool
        if (relayPool) {
            log('Closing relay pool...', 'INFO');
            const url = relayConnectionUrl.value.trim();
            if (url) {
                try {
                    await relayPool.close([url]);
                } catch (e) {
                    console.log('Pool close error (non-critical):', e.message);
                }
            }
            relayPool = null;
            subscriptionId = null;
        }

        // Reset subscription flags
        isSubscribed = false;
        isSubscribing = false;

        await nlLite.logout();

        userPubkey = null;
        isLoggedIn = false;
        currentConfig = null;

        // Reset relay connection state
        isRelayConnected = false;
        relayPubkey = null;

        // Reset UI - hide profile and show login modal
        hideProfileFromHeader();

        updateConfigStatus(false);
        updateAdminSectionsVisibility();

        log('Logged out successfully', 'INFO');
    } catch (error) {
        log('Logout failed: ' + error.message, 'ERROR');
    }
}

function updateConfigStatus(loaded) {
    if (loaded) {
        configDisplay.classList.remove('hidden');
    } else {
        configDisplay.classList.add('hidden');
    }
}



// Generate random subscription ID (avoiding colons which are rejected by relay)
function generateSubId() {
    // Use only alphanumeric characters, underscores, hyphens, and commas
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-,';
    let result = '';
    for (let i = 0; i < 12; i++) {
        result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
}

// WebSocket monitoring function to attach to SimplePool connections
function attachWebSocketMonitoring(relayPool, url) {
    console.log('🔍 Attaching WebSocket monitoring to SimplePool...');

    // SimplePool stores connections in _conn object
    if (relayPool && relayPool._conn) {
        // Monitor when connections are created
        const originalGetConnection = relayPool._conn[url];
        if (originalGetConnection) {
            console.log('📡 Found existing connection for URL:', url);

            // Try to access the WebSocket if it's available
            const conn = relayPool._conn[url];
            if (conn && conn.ws) {
                attachWebSocketEventListeners(conn.ws, url);
            }
        }

        // Override the connection getter to monitor new connections
        const originalConn = relayPool._conn;
        relayPool._conn = new Proxy(originalConn, {
            get(target, prop) {
                const conn = target[prop];
                if (conn && conn.ws && !conn.ws._monitored) {
                    console.log('🔗 New WebSocket connection detected for:', prop);
                    attachWebSocketEventListeners(conn.ws, prop);
                    conn.ws._monitored = true;
                }
                return conn;
            },
            set(target, prop, value) {
                if (value && value.ws && !value.ws._monitored) {
                    console.log('🔗 WebSocket connection being set for:', prop);
                    attachWebSocketEventListeners(value.ws, prop);
                    value.ws._monitored = true;
                }
                target[prop] = value;
                return true;
            }
        });
    }

    console.log('✅ WebSocket monitoring attached');
}

function attachWebSocketEventListeners(ws, url) {
    console.log(`🎯 Attaching event listeners to WebSocket for ${url}`);

    // Log connection open
    ws.addEventListener('open', (event) => {
        console.log(`🔓 WebSocket OPEN for ${url}:`, {
            readyState: ws.readyState,
            url: ws.url,
            protocol: ws.protocol,
            extensions: ws.extensions
        });
    });

    // Log incoming messages with full details
    ws.addEventListener('message', (event) => {
        try {
            const data = event.data;
            console.log(`📨 WebSocket MESSAGE from ${url}:`, {
                type: event.type,
                data: data,
                dataLength: data.length,
                timestamp: new Date().toISOString()
            });

            // Try to parse as JSON for Nostr messages
            try {
                const parsed = JSON.parse(data);
                if (Array.isArray(parsed)) {
                    const [type, ...args] = parsed;
                    console.log(`📨 Parsed Nostr message [${type}]:`, args);
                } else {
                    console.log(`📨 Parsed JSON:`, parsed);
                }
            } catch (parseError) {
                console.log(`📨 Raw message (not JSON):`, data);
            }
        } catch (error) {
            console.error(`❌ Error processing WebSocket message from ${url}:`, error);
        }
    });

    // Log connection close with details
    ws.addEventListener('close', (event) => {
        console.log(`🔒 WebSocket CLOSE for ${url}:`, {
            code: event.code,
            reason: event.reason,
            wasClean: event.wasClean,
            readyState: ws.readyState,
            timestamp: new Date().toISOString()
        });
    });

    // Log errors with full details
    ws.addEventListener('error', (event) => {
        console.error(`❌ WebSocket ERROR for ${url}:`, {
            type: event.type,
            target: event.target,
            readyState: ws.readyState,
            url: ws.url,
            timestamp: new Date().toISOString()
        });

        // Log additional WebSocket state
        console.error(`❌ WebSocket state details:`, {
            readyState: ws.readyState,
            bufferedAmount: ws.bufferedAmount,
            protocol: ws.protocol,
            extensions: ws.extensions,
            binaryType: ws.binaryType
        });
    });

    // Override send method to log outgoing messages
    const originalSend = ws.send;
    ws.send = function(data) {
        console.log(`📤 WebSocket SEND to ${url}:`, {
            data: data,
            dataLength: data.length,
            readyState: ws.readyState,
            timestamp: new Date().toISOString()
        });

        // Try to parse outgoing Nostr messages
        try {
            const parsed = JSON.parse(data);
            if (Array.isArray(parsed)) {
                const [type, ...args] = parsed;
                console.log(`📤 Outgoing Nostr message [${type}]:`, args);
            } else {
                console.log(`📤 Outgoing JSON:`, parsed);
            }
        } catch (parseError) {
            console.log(`📤 Outgoing raw message (not JSON):`, data);
        }

        return originalSend.call(this, data);
    };

    console.log(`✅ Event listeners attached to WebSocket for ${url}`);
}

// Configuration subscription using nostr-tools SimplePool
async function subscribeToConfiguration() {
    try {
        console.log('=== SUBSCRIBE TO CONFIGURATION ===');
        console.log('Call stack:', new Error().stack);

        // If pool already exists and subscribed, we're done
        if (relayPool && isSubscribed) {
            console.log('✅ Already subscribed, reusing existing pool');
            return true;
        }

        // Prevent concurrent subscription attempts
        if (isSubscribing) {
            console.log('⚠️ Subscription already in progress');
            return false;
        }

        isSubscribing = true;

        const url = relayConnectionUrl.value.trim();
        if (!url) {
            console.error('No relay URL configured');
            isSubscribing = false;
            return false;
        }

        console.log(`🔌 Connecting to relay: ${url}`);

        // Create pool ONLY if it doesn't exist
        if (!relayPool) {
            console.log('✨ Creating NEW SimplePool for admin operations');
            relayPool = new window.NostrTools.SimplePool();
            
            // Attach WebSocket monitoring to the new pool
            attachWebSocketMonitoring(relayPool, url);
        } else {
            console.log('♻️ Reusing existing SimplePool');
        }

        subscriptionId = generateSubId();

        console.log(`📝 Generated subscription ID: ${subscriptionId}`);
        console.log(`👤 User pubkey: ${userPubkey}`);
        console.log(`🎯 About to call relayPool.subscribeMany with URL: ${url}`);
        console.log(`📊 relayPool._conn before subscribeMany:`, Object.keys(relayPool._conn || {}));
        
        // Mark as subscribed BEFORE calling subscribeMany to prevent race conditions
        isSubscribed = true;

        // Subscribe to kind 23457 events (admin response events), kind 4 (NIP-04 DMs), kind 1059 (NIP-17 GiftWrap), kind 24567 (ephemeral monitoring events), and relay events (kinds 0, 10050, 10002)
        console.log('🔔 Calling relayPool.subscribeMany with all filters...');
        const subscription = relayPool.subscribeMany([url], [{
            since: Math.floor(Date.now() / 1000) - 5,  // Look back 5 seconds to avoid race condition
            kinds: [23457],
            authors: [getRelayPubkey()], // Only listen to responses from the relay
            "#p": [userPubkey], // Only responses directed to this user
            limit: 50
        }, {
            since: Math.floor(Date.now() / 1000),
            kinds: [4], // NIP-04 Direct Messages
            authors: [getRelayPubkey()], // Only listen to DMs from the relay
            "#p": [userPubkey], // Only DMs directed to this user
            limit: 50
        }, {
            since: Math.floor(Date.now() / 1000) - (2 * 24 * 60 * 60), // Look back 2 days for NIP-59 randomized timestamps
            kinds: [1059], // NIP-17 GiftWrap events
            "#p": [userPubkey], // Only GiftWrap events addressed to this user
            limit: 50
        }, {
            since: Math.floor(Date.now() / 1000), // Start from current time
            kinds: [24567], // Real-time ephemeral monitoring events
            authors: [getRelayPubkey()], // Only listen to monitoring events from the relay
            "#d": isLoggedIn ? ["event_kinds", "time_stats", "top_pubkeys", "subscription_details", "cpu_metrics"] : ["event_kinds", "time_stats", "top_pubkeys", "cpu_metrics"], // Include subscription_details only when authenticated, cpu_metrics available to all
            limit: 50
        }, {
            since: Math.floor(Date.now() / 1000) - (24 * 60 * 60), // Look back 24 hours for relay events
            kinds: [0, 10050, 10002], // Relay events: metadata, DM relays, relay list
            authors: [getRelayPubkey()], // Only listen to relay's own events
            limit: 10
        }], {
            async onevent(event) {
                // Simplified logging - one line per event
                if (event.kind === 24567) {
                    const dTag = event.tags.find(tag => tag[0] === 'd');
                    const dataType = dTag ? dTag[1] : 'unknown';
                    // console.log(`📊 Monitoring event: ${dataType}`);
                } else {
                    console.log(`📨 Event received: kind ${event.kind}`);
                }

                // Handle NIP-04 DMs
                if (event.kind === 4) {
                    try {
                        // Decrypt the DM content
                        const decryptedContent = await window.nostr.nip04.decrypt(event.pubkey, event.content);
                        log(`Received NIP-04 DM from relay: ${decryptedContent.substring(0, 50)}...`, 'INFO');

                        // Add to inbox
                        const timestamp = new Date(event.created_at * 1000).toLocaleString();
                        addMessageToInbox('received', decryptedContent, timestamp, event.pubkey);

                        // Log for testing
                        if (typeof logTestEvent === 'function') {
                            logTestEvent('RECV', `NIP-04 DM: ${decryptedContent}`, 'DM');
                        }
                    } catch (decryptError) {
                        log(`Failed to decrypt NIP-04 DM: ${decryptError.message}`, 'ERROR');
                        if (typeof logTestEvent === 'function') {
                            logTestEvent('ERROR', `Failed to decrypt DM: ${decryptError.message}`, 'DM');
                        }
                    }
                    return;
                }

                // Handle NIP-17 GiftWrap DMs
                if (event.kind === 1059) {
                    console.log(`📨 RECEIVED KIND 1059 EVENT:`, {
                        id: event.id,
                        pubkey: event.pubkey,
                        created_at: event.created_at,
                        content: event.content.substring(0, 100) + '...',
                        tags: event.tags
                    });

                    try {
                        // Step 1: Unwrap gift wrap to get seal
                        const sealJson = await window.nostr.nip44.decrypt(event.pubkey, event.content);
                        console.log(`🔓 STEP 1 - Unwrapped gift wrap:`, sealJson.substring(0, 100) + '...');
                        const seal = safeJsonParse(sealJson);
                        if (!seal || seal.kind !== 13) {
                            throw new Error('Unwrapped content is not a valid seal (kind 13)');
                        }
                        console.log(`✅ Seal validated:`, { kind: seal.kind, pubkey: seal.pubkey.substring(0, 16) + '...' });

                        // Step 2: Unseal to get rumor
                        const rumorJson = await window.nostr.nip44.decrypt(seal.pubkey, seal.content);
                        console.log(`🔓 STEP 2 - Unsealed rumor:`, rumorJson.substring(0, 100) + '...');
                        const rumor = safeJsonParse(rumorJson);
                        if (!rumor || rumor.kind !== 14) {
                            throw new Error('Unsealed content is not a valid rumor (kind 14)');
                        }
                        console.log(`✅ Rumor validated:`, { kind: rumor.kind, pubkey: rumor.pubkey.substring(0, 16) + '...', content: rumor.content.substring(0, 50) + '...' });

                        log(`Received NIP-17 DM from relay: ${rumor.content.substring(0, 50)}...`, 'INFO');

                        // Add to inbox
                        const timestamp = new Date(event.created_at * 1000).toLocaleString();
                        addMessageToInbox('received', rumor.content, timestamp, rumor.pubkey);

                        // Log for testing
                        if (typeof logTestEvent === 'function') {
                            logTestEvent('RECV', `NIP-17 DM: ${rumor.content}`, 'DM');
                        }
                    } catch (unwrapError) {
                        console.error(`❌ NIP-17 DM UNWRAP FAILED:`, unwrapError);
                        log(`Failed to unwrap NIP-17 DM: ${unwrapError.message}`, 'ERROR');
                        if (typeof logTestEvent === 'function') {
                            logTestEvent('ERROR', `Failed to unwrap DM: ${unwrapError.message}`, 'DM');
                        }
                    }
                    return;
                }

                // Handle admin response events (kind 23457)
                if (event.kind === 23457) {
                    // Log all received messages for testing
                    if (typeof logTestEvent === 'function') {
                        logTestEvent('RECV', `Admin response event: ${JSON.stringify(event)}`, 'EVENT');
                    }

                    // Process admin response event
                    processAdminResponse(event);
                }

                // Handle monitoring events (kind 24567 - ephemeral)
                if (event.kind === 24567) {
                    // Process monitoring event (logging done above)
                    processMonitoringEvent(event);
                }

                // Handle relay events (kinds 0, 10050, 10002)
                if ([0, 10050, 10002].includes(event.kind)) {
                    handleRelayEventReceived(event);
                }
            },
            oneose() {
                console.log('EOSE received - End of stored events');
                console.log('Current config after EOSE:', currentConfig);

                if (!currentConfig) {
                    console.log('No configuration events were received');
                }
            },
            onclose(reason) {
                console.log('Subscription closed:', reason);
                // Reset subscription state to allow re-subscription
                isSubscribed = false;
                isSubscribing = false;
                isRelayConnected = false;
                updateConfigStatus(false);
                log('WebSocket connection closed - subscription state reset', 'WARNING');
            }
        });

        // Store subscription for cleanup
        relayPool.currentSubscription = subscription;

        // Mark as subscribed
        isSubscribed = true;
        isSubscribing = false;

        console.log('✅ Subscription established successfully');
        return true;

    } catch (error) {
        console.error('Configuration subscription failed:', error.message);
        console.error('Configuration subscription failed:', error);
        console.error('Error stack:', error.stack);
        isSubscribing = false;
        return false;
    }
}

// Process admin response events (kind 23457)
async function processAdminResponse(event) {
    try {
        console.log('=== PROCESSING ADMIN RESPONSE ===');
        console.log('Response event:', event);

        // Verify this is a kind 23457 admin response event
        if (event.kind !== 23457) {
            console.log('Ignoring non-admin response event, kind:', event.kind);
            return;
        }

        // Verify the event is from the relay
        const expectedRelayPubkey = getRelayPubkey();
        if (event.pubkey !== expectedRelayPubkey) {
            console.log('Ignoring response from unknown pubkey:', event.pubkey);
            return;
        }

        // Decrypt the NIP-44 encrypted content
        const decryptedContent = await decryptFromRelay(event.content);
        if (!decryptedContent) {
            throw new Error('Failed to decrypt admin response content');
        }

        // console.log('Decrypted admin response:', decryptedContent);

        // Try to parse as JSON first, if it fails treat as plain text
        let responseData;
        try {
            responseData = JSON.parse(decryptedContent);
            console.log('Parsed response data:', responseData);
        } catch (parseError) {
            // Not JSON - treat as plain text response
            console.log('Response is plain text, not JSON');
            responseData = {
                plain_text: true,
                message: decryptedContent
            };
        }

        // Log the response for testing
        if (typeof logTestEvent === 'function') {
            logTestEvent('RECV', `Decrypted response: ${JSON.stringify(responseData)}`, 'RESPONSE');
        }

        // Handle different types of admin responses
        handleAdminResponseData(responseData);

    } catch (error) {
        console.error('Error processing admin response:', error);
        if (typeof logTestEvent === 'function') {
            logTestEvent('ERROR', `Failed to process admin response: ${error.message}`, 'ERROR');
        }
    }
}

// Initialize real-time event rate chart
function initializeEventRateChart() {
    try {
        console.log('=== INITIALIZING EVENT RATE CHART ===');
        
        const chartContainer = document.getElementById('event-rate-chart');
        console.log('Chart container found:', chartContainer);
        
        if (!chartContainer) {
            console.log('Event rate chart container not found');
            return;
        }

        // Show immediate placeholder content
        chartContainer.textContent = 'Initializing event rate chart...';
        console.log('Set placeholder content');

        // Check if ASCIIBarChart is available
        console.log('Checking ASCIIBarChart availability...');
        console.log('typeof ASCIIBarChart:', typeof ASCIIBarChart);
        console.log('window.ASCIIBarChart:', window.ASCIIBarChart);
        
        if (typeof ASCIIBarChart === 'undefined') {
            console.log('ASCIIBarChart not available - text_graph.js may not be loaded');
            // Show a more detailed error message
            chartContainer.innerHTML = `
                <div style="color: var(--accent-color); font-family: var(--font-family); padding: 10px;">
                    ⚠️ Chart library not loaded<br>
                    Check: /text_graph/text_graph.js<br>
                    <small>Real-time event visualization unavailable</small>
                </div>
            `;
            return;
        }

        // Create stub elements that the chart expects for info display
        createChartStubElements();

        console.log('Creating ASCIIBarChart instance...');
        
        // Initialize the chart with correct parameters based on text_graph.js API
        eventRateChart = new ASCIIBarChart('event-rate-chart', {
            maxHeight: 11,          // Chart height in lines
            maxDataPoints: 76,      // Show last 76 bins (5+ minutes of history)
            title: 'New Events',   // Chart title
            xAxisLabel: '',        // No X-axis label
            yAxisLabel: '',        // No Y-axis label
            autoFitWidth: true,    // Enable responsive font sizing
            useBinMode: true,      // Enable time bin aggregation
            binDuration: 4000,     // 4-second time bins
            xAxisLabelFormat: 'elapsed', // Show elapsed time labels
            debug: false           // Disable debug logging
        });

        console.log('ASCIIBarChart instance created:', eventRateChart);
        console.log('Chart container content after init:', chartContainer.textContent);
        console.log('Chart container innerHTML after init:', chartContainer.innerHTML);
        
        // Force an initial render
        if (eventRateChart && typeof eventRateChart.render === 'function') {
            console.log('Forcing initial render...');
            eventRateChart.render();
            console.log('Chart container content after render:', chartContainer.textContent);
        }

        console.log('Event rate chart initialized successfully');
        log('Real-time event rate chart initialized', 'INFO');

    } catch (error) {
        console.error('Failed to initialize event rate chart:', error);
        console.error('Error stack:', error.stack);
        log(`Failed to initialize event rate chart: ${error.message}`, 'ERROR');
        
        // Show detailed error message in the container
        const chartContainer = document.getElementById('event-rate-chart');
        if (chartContainer) {
            chartContainer.innerHTML = `
                <div style="color: var(--error-color, #ff6b6b); font-family: var(--font-family); padding: 10px;">
                    ❌ Chart initialization failed<br>
                    <small>${error.message}</small><br>
                    <small>Check browser console for details</small>
                </div>
            `;
        }
    }
}

// Create stub elements that the ASCIIBarChart expects for info display
function createChartStubElements() {
    const stubIds = ['values', 'max-value', 'scale', 'count'];
    
    stubIds.forEach(id => {
        if (!document.getElementById(id)) {
            const stubElement = document.createElement('div');
            stubElement.id = id;
            stubElement.style.display = 'none'; // Hide stub elements
            document.body.appendChild(stubElement);
        }
    });
    
    console.log('Chart stub elements created');
}

// Handle monitoring events (kind 24567 - ephemeral)
async function processMonitoringEvent(event) {
    try {
        // Verify this is a kind 24567 ephemeral monitoring event
        if (event.kind !== 24567) {
            return;
        }

        // Verify the event is from the relay
        const expectedRelayPubkey = getRelayPubkey();
        if (event.pubkey !== expectedRelayPubkey) {
            return;
        }

        // Check the d-tag to determine which type of monitoring event this is
        const dTag = event.tags.find(tag => tag[0] === 'd');
        if (!dTag) {
            return;
        }

        // Parse the monitoring data (content is JSON, not encrypted for monitoring events)
        const monitoringData = JSON.parse(event.content);

        // Route to appropriate handler based on d-tag (no verbose logging)
        switch (dTag[1]) {
            case 'event_kinds':
                updateStatsFromMonitoringEvent(monitoringData);
                break;

            case 'time_stats':
                updateStatsFromTimeMonitoringEvent(monitoringData);
                break;

            case 'top_pubkeys':
                updateStatsFromTopPubkeysMonitoringEvent(monitoringData);
                break;


            case 'subscription_details':
                // Only process subscription details if user is authenticated
                if (isLoggedIn) {
                    updateStatsFromSubscriptionDetailsMonitoringEvent(monitoringData);
                    // Also update the active subscriptions count from this data
                    if (monitoringData.data && monitoringData.data.subscriptions) {
                        updateStatsCell('active-subscriptions', monitoringData.data.subscriptions.length.toString());
                    }
                }
                break;

            case 'cpu_metrics':
                updateStatsFromCpuMonitoringEvent(monitoringData);
                break;

            default:
                return;
        }

    } catch (error) {
        console.error('Error processing monitoring event:', error);
        log(`Failed to process monitoring event: ${error.message}`, 'ERROR');
    }
}

// Handle different types of admin response data
function handleAdminResponseData(responseData) {
    try {
        console.log('=== HANDLING ADMIN RESPONSE DATA ===');
        console.log('Response data:', responseData);
        console.log('Response query_type:', responseData.query_type);

        // Handle plain text responses (from create_relay_event and other commands)
        if (responseData.plain_text) {
            console.log('Handling plain text response');
            log(responseData.message, 'INFO');
            
            // Show the message in relay events status if we're on that page
            if (currentPage === 'relay-events') {
                // Try to determine which kind based on message content
                if (responseData.message.includes('Kind: 0')) {
                    showStatus('kind0-status', responseData.message, 'success');
                } else if (responseData.message.includes('Kind: 10050')) {
                    showStatus('kind10050-status', responseData.message, 'success');
                } else if (responseData.message.includes('Kind: 10002')) {
                    showStatus('kind10002-status', responseData.message, 'success');
                }
            }
            return;
        }

        // Handle auth query responses - updated to match backend response types
        if (responseData.query_type &&
            (responseData.query_type.includes('auth_rules') ||
                responseData.query_type.includes('auth'))) {
            console.log('Routing to auth query handler');
            handleAuthQueryResponse(responseData);
            return;
        }

        // Handle config update responses specifically
        if (responseData.query_type === 'config_update') {
            console.log('Routing to config update handler');
            handleConfigUpdateResponse(responseData);
            return;
        }

        // Handle config query responses - updated to match backend response types
        if (responseData.query_type &&
            (responseData.query_type.includes('config') ||
                responseData.query_type.startsWith('config_'))) {
            console.log('Routing to config query handler');
            handleConfigQueryResponse(responseData);
            return;
        }

        // Handle system command responses
        if (responseData.command) {
            console.log('Routing to system command handler');
            handleSystemCommandResponse(responseData);
            return;
        }

        // Handle auth rule modification responses
        if (responseData.operation || responseData.rules_processed !== undefined) {
            console.log('Routing to auth rule modification handler');
            handleAuthRuleResponse(responseData);
            return;
        }

        // Handle stats query responses
        if (responseData.query_type === 'stats_query') {
            console.log('Routing to stats query handler');
            handleStatsQueryResponse(responseData);
            return;
        }

        // Handle SQL query responses
        if (responseData.query_type === 'sql_query') {
            console.log('Routing to SQL query handler');
            handleSqlQueryResponse(responseData);
            return;
        }

        // Generic response handling
        console.log('Using generic response handler');
        if (typeof logTestEvent === 'function') {
            logTestEvent('RECV', `Generic admin response: ${JSON.stringify(responseData)}`, 'RESPONSE');
        }

    } catch (error) {
        console.error('Error handling admin response data:', error);
        if (typeof logTestEvent === 'function') {
            logTestEvent('ERROR', `Failed to handle response data: ${error.message}`, 'ERROR');
        }
    }
}

// Handle config query responses
function handleConfigQueryResponse(responseData) {
    console.log('=== CONFIG QUERY RESPONSE ===');
    console.log('Query type:', responseData.query_type);
    console.log('Total results:', responseData.total_results);
    console.log('Data:', responseData.data);

    // Convert the config response data to the format expected by displayConfiguration
    if (responseData.data && responseData.data.length > 0) {
        console.log('Converting config response to display format...');

        // Create a synthetic event structure for displayConfiguration
        const syntheticEvent = {
            id: 'config_response_' + Date.now(),
            pubkey: getRelayPubkey(),
            created_at: Math.floor(Date.now() / 1000),
            kind: 'config_response',
            content: 'Configuration from admin API',
            tags: []
        };

        // Convert config data to tags format
        responseData.data.forEach(config => {
            const key = config.key || config.config_key;
            const value = config.value || config.config_value;
            if (key && value !== undefined) {
                syntheticEvent.tags.push([key, value]);
            }
        });

        console.log('Synthetic event created:', syntheticEvent);
        console.log('Calling displayConfiguration with synthetic event...');

        // Display the configuration using the original display function
        displayConfiguration(syntheticEvent);

        // Update relay info in header with config data
        updateStoredRelayInfo(responseData);

        // Initialize toggle buttons with config data
        initializeToggleButtonsFromConfig(responseData);

        log(`Configuration loaded: ${responseData.total_results} parameters`, 'INFO');
    } else {
        console.log('No configuration data received');
        updateConfigStatus(false);
    }

    // Also log to test interface for debugging
    if (typeof logTestEvent === 'function') {
        logTestEvent('RECV', `Config query response: ${responseData.query_type}, ${responseData.total_results} results`, 'CONFIG_QUERY');

        if (responseData.data && responseData.data.length > 0) {
            logTestEvent('RECV', '=== CONFIGURATION VALUES ===', 'CONFIG');
            responseData.data.forEach((config, index) => {
                const key = config.key || config.config_key || `config_${index}`;
                const value = config.value || config.config_value || 'undefined';
                const category = config.category || 'general';
                const dataType = config.data_type || 'string';

                logTestEvent('RECV', `${key}: ${value} (${dataType}, ${category})`, 'CONFIG');
            });
            logTestEvent('RECV', '=== END CONFIGURATION VALUES ===', 'CONFIG');
        } else {
            logTestEvent('RECV', 'No configuration values found', 'CONFIG_QUERY');
        }
    }
}

// Handle config update responses
function handleConfigUpdateResponse(responseData) {
    console.log('=== CONFIG UPDATE RESPONSE ===');
    console.log('Query type:', responseData.query_type);
    console.log('Status:', responseData.status);
    console.log('Data:', responseData.data);

    if (responseData.status === 'success') {
        const updatesApplied = responseData.updates_applied || 0;
        log(`Configuration updated successfully: ${updatesApplied} parameters changed`, 'INFO');

        // Show success message with details
        if (responseData.data && Array.isArray(responseData.data)) {
            responseData.data.forEach((config, index) => {
                if (config.status === 'success') {
                    log(`✓ ${config.key}: ${config.value} (${config.data_type})`, 'INFO');
                } else {
                    log(`✗ ${config.key}: ${config.error || 'Failed to update'}`, 'ERROR');
                }
            });
        }

        // Configuration updated successfully - user can manually refresh using Fetch Config button
        log('Configuration updated successfully. Click "Fetch Config" to refresh the display.', 'INFO');

    } else {
        const errorMessage = responseData.message || responseData.error || 'Unknown error';
        log(`Configuration update failed: ${errorMessage}`, 'ERROR');

        // Show detailed error information if available
        if (responseData.data && Array.isArray(responseData.data)) {
            responseData.data.forEach((config, index) => {
                if (config.status === 'error') {
                    log(`✗ ${config.key}: ${config.error || 'Failed to update'}`, 'ERROR');
                }
            });
        }
    }

    // Log to test interface for debugging
    if (typeof logTestEvent === 'function') {
        logTestEvent('RECV', `Config update response: ${responseData.status}`, 'CONFIG_UPDATE');

        if (responseData.data && responseData.data.length > 0) {
            responseData.data.forEach((config, index) => {
                const status = config.status === 'success' ? '✓' : '✗';
                const message = config.status === 'success' ?
                    `${config.key} = ${config.value}` :
                    `${config.key}: ${config.error || 'Failed'}`;
                logTestEvent('RECV', `${status} ${message}`, 'CONFIG_UPDATE');
            });
        } else {
            logTestEvent('RECV', 'No configuration update details received', 'CONFIG_UPDATE');
        }
    }
}

// Handle auth query responses
function handleAuthQueryResponse(responseData) {
    console.log('=== AUTH QUERY RESPONSE ===');
    console.log('Query type:', responseData.query_type);
    console.log('Total results:', responseData.total_results);
    console.log('Data:', responseData.data);

    // Update the current auth rules with the response data
    if (responseData.data && Array.isArray(responseData.data)) {
        currentAuthRules = responseData.data;
        console.log('Updated currentAuthRules with', currentAuthRules.length, 'rules');

        // Always show the auth rules table when we receive data (no VIEW RULES button anymore)
        console.log('Auto-showing auth rules table since we received data...');
        showAuthRulesTable();

        updateAuthRulesStatus('loaded');
        log(`Loaded ${responseData.total_results} auth rules from relay`, 'INFO');
    } else {
        currentAuthRules = [];
        console.log('No auth rules data received, cleared currentAuthRules');

        // Show empty table (no VIEW RULES button anymore)
        console.log('Auto-showing auth rules table with empty data...');
        showAuthRulesTable();

        updateAuthRulesStatus('loaded');
        log('No auth rules found on relay', 'INFO');
    }

    if (typeof logTestEvent === 'function') {
        logTestEvent('RECV', `Auth query response: ${responseData.query_type}, ${responseData.total_results} results`, 'AUTH_QUERY');

        if (responseData.data && responseData.data.length > 0) {
            responseData.data.forEach((rule, index) => {
                logTestEvent('RECV', `Rule ${index + 1}: ${rule.rule_type} - ${rule.pattern_value || rule.rule_target}`, 'AUTH_RULE');
            });
        } else {
            logTestEvent('RECV', 'No auth rules found', 'AUTH_QUERY');
        }
    }
}

// Handle system command responses
function handleSystemCommandResponse(responseData) {
    console.log('=== SYSTEM COMMAND RESPONSE ===');
    console.log('Command:', responseData.command);
    console.log('Status:', responseData.status);

    // Handle delete auth rule responses
    if (responseData.command === 'delete_auth_rule') {
        if (responseData.status === 'success') {
            log('Auth rule deleted successfully', 'INFO');
            // Refresh the auth rules display
            loadAuthRules();
        } else {
            log(`Failed to delete auth rule: ${responseData.message || 'Unknown error'}`, 'ERROR');
        }
    }

    // Handle clear all auth rules responses
    if (responseData.command === 'clear_all_auth_rules') {
        if (responseData.status === 'success') {
            const rulesCleared = responseData.rules_cleared || 0;
            log(`Successfully cleared ${rulesCleared} auth rules`, 'INFO');
            // Clear local auth rules and refresh display
            currentAuthRules = [];
            displayAuthRules(currentAuthRules);
        } else {
            log(`Failed to clear auth rules: ${responseData.message || 'Unknown error'}`, 'ERROR');
        }
    }

    if (typeof logTestEvent === 'function') {
        logTestEvent('RECV', `System command response: ${responseData.command} - ${responseData.status}`, 'SYSTEM_CMD');
    }
}

// Handle auth rule modification responses
function handleAuthRuleResponse(responseData) {
    console.log('=== AUTH RULE MODIFICATION RESPONSE ===');
    console.log('Operation:', responseData.operation);
    console.log('Status:', responseData.status);

    // Handle auth rule addition/modification responses
    if (responseData.status === 'success') {
        const rulesProcessed = responseData.rules_processed || 0;
        log(`Successfully processed ${rulesProcessed} auth rule modifications`, 'INFO');

        // Refresh the auth rules display to show the new rules
        if (authRulesTableContainer && authRulesTableContainer.style.display !== 'none') {
            loadAuthRules();
        }
    } else {
        log(`Failed to process auth rule modifications: ${responseData.message || 'Unknown error'}`, 'ERROR');
    }

    if (typeof logTestEvent === 'function') {
        logTestEvent('RECV', `Auth rule response: ${responseData.operation} - ${responseData.status}`, 'AUTH_RULE');

        if (responseData.processed_rules) {
            responseData.processed_rules.forEach((rule, index) => {
                logTestEvent('RECV', `Processed rule ${index + 1}: ${rule.rule_type} - ${rule.pattern_value || rule.rule_target}`, 'AUTH_RULE');
            });
        }
    }
}

// Helper function to decrypt content from relay using NIP-44
async function decryptFromRelay(encryptedContent) {
    try {
        console.log('Decrypting content from relay...');

        // Get the relay public key for decryption
        const relayPubkey = getRelayPubkey();

        // Use NIP-07 extension's NIP-44 decrypt method
        if (!window.nostr || !window.nostr.nip44) {
            throw new Error('NIP-44 decryption not available via NIP-07 extension');
        }

        const decryptedContent = await window.nostr.nip44.decrypt(relayPubkey, encryptedContent);

        if (!decryptedContent) {
            throw new Error('NIP-44 decryption returned empty result');
        }

        console.log('Successfully decrypted content from relay');
        return decryptedContent;

    } catch (error) {
        console.error('NIP-44 decryption failed:', error);
        throw error;
    }
}

// Fetch configuration using admin API
async function fetchConfiguration() {
    try {
        console.log('=== FETCHING CONFIGURATION VIA ADMIN API ===');

        // Require both login and relay connection
        if (!isLoggedIn || !userPubkey) {
            throw new Error('Must be logged in to fetch configuration');
        }

        if (!isRelayConnected || !relayPubkey) {
            throw new Error('Must be connected to relay to fetch configuration. Please use the Relay Connection section first.');
        }

        // First establish subscription to receive responses (only if not already subscribed)
        const subscriptionResult = await subscribeToConfiguration();
        if (!subscriptionResult) {
            throw new Error('Failed to establish admin response subscription');
        }

        // Wait a moment for subscription to be established (only if we just created it)
        if (!isSubscribed) {
            await new Promise(resolve => setTimeout(resolve, 500));
        }

        // Send config query command if logged in
        if (isLoggedIn && userPubkey && relayPool) {
            console.log('Sending config query command...');

            // Create command array for getting configuration
            const command_array = ["config_query", "all"];

            // Encrypt the command array directly using NIP-44
            const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
            if (!encrypted_content) {
                throw new Error('Failed to encrypt command array');
            }

            // Create single kind 23456 admin event
            const configEvent = {
                kind: 23456,
                pubkey: userPubkey,
                created_at: Math.floor(Date.now() / 1000),
                tags: [["p", getRelayPubkey()]],
                content: encrypted_content
            };

            // Sign the event
            const signedEvent = await window.nostr.signEvent(configEvent);
            if (!signedEvent || !signedEvent.sig) {
                throw new Error('Event signing failed');
            }

            console.log('Config query event signed, publishing...');

            // Publish via SimplePool with detailed error diagnostics
            const url = relayConnectionUrl.value.trim();
            const publishPromises = relayPool.publish([url], signedEvent);

            // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
            const results = await Promise.allSettled(publishPromises);

            // Log detailed publish results for diagnostics
            let successCount = 0;
            results.forEach((result, index) => {
                if (result.status === 'fulfilled') {
                    successCount++;
                    console.log(`✅ Relay ${index} (${url}): Event published successfully`);
                    if (typeof logTestEvent === 'function') {
                        logTestEvent('INFO', `Relay ${index} publish success`, 'PUBLISH');
                    }
                } else {
                    console.error(`❌ Relay ${index} (${url}): Publish failed:`, result.reason);
                    if (typeof logTestEvent === 'function') {
                        logTestEvent('ERROR', `Relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
                    }
                }
            });

            // Throw error if all relays failed
            if (successCount === 0) {
                const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
                throw new Error(`All relays rejected the event. Details: ${errorDetails}`);
            }

            console.log('Config query command sent successfully - waiting for response...');

        } else {
            console.log('Not logged in - only subscription established for testing');
        }

        return true;

    } catch (error) {
        console.error('Failed to fetch configuration:', error);
        return false;
    }
}

function displayConfiguration(event) {
    try {
        console.log('=== DISPLAYING CONFIGURATION EVENT ===');
        console.log('Event received for display:', event);

        currentConfig = event;

        // Clear existing table
        configTableBody.innerHTML = '';

        // Display tags (editable configuration parameters only)
        console.log(`Processing ${event.tags.length} configuration parameters`);
        event.tags.forEach((tag, index) => {
            if (tag.length >= 2) {
                const row = document.createElement('tr');
                const key = tag[0];
                const value = tag[1];

                // Create editable input for value
                const valueInput = document.createElement('input');
                valueInput.type = 'text';
                valueInput.value = value;
                valueInput.className = 'config-value-input';
                valueInput.dataset.key = key;
                valueInput.dataset.originalValue = value;
                valueInput.dataset.rowIndex = index;

                // Create clickable Actions cell
                const actionsCell = document.createElement('td');
                actionsCell.className = 'config-actions-cell';
                actionsCell.textContent = 'SAVE';
                actionsCell.dataset.key = key;
                actionsCell.dataset.originalValue = value;
                actionsCell.dataset.rowIndex = index;

                // Initially hide the SAVE text
                actionsCell.style.color = 'transparent';

                // Show SAVE text and make clickable when value changes
                valueInput.addEventListener('input', function () {
                    if (this.value !== this.dataset.originalValue) {
                        actionsCell.style.color = 'var(--primary-color)';
                        actionsCell.style.cursor = 'pointer';
                        actionsCell.onclick = () => saveIndividualConfig(key, valueInput.value, valueInput.dataset.originalValue, actionsCell);
                    } else {
                        actionsCell.style.color = 'transparent';
                        actionsCell.style.cursor = 'default';
                        actionsCell.onclick = null;
                    }
                });

                row.innerHTML = `<td>${key}</td><td></td>`;
                row.cells[1].appendChild(valueInput);
                row.appendChild(actionsCell);
                configTableBody.appendChild(row);
            }
        });

        // Show message if no configuration parameters found
        if (event.tags.length === 0) {
            const row = document.createElement('tr');
            row.innerHTML = `<td colspan="3" style="text-align: center; font-style: italic;">No configuration parameters found</td>`;
            configTableBody.appendChild(row);
        }

        console.log('Configuration display completed successfully');
        updateConfigStatus(true);

    } catch (error) {
        console.error('Error in displayConfiguration:', error.message);
        console.error('Display configuration error:', error);
    }
}

// Save individual configuration parameter
async function saveIndividualConfig(key, newValue, originalValue, actionsCell) {
    if (!isLoggedIn || !userPubkey) {
        log('Must be logged in to save configuration', 'ERROR');
        return;
    }

    if (!currentConfig) {
        log('No current configuration to update', 'ERROR');
        return;
    }

    // Don't save if value hasn't changed
    if (newValue === originalValue) {
        return;
    }

    try {
        log(`Saving individual config: ${key} = ${newValue}`, 'INFO');

        // Determine data type based on key name
        let dataType = 'string';
        if (['max_connections', 'pow_min_difficulty', 'nip42_challenge_timeout', 'max_subscriptions_per_client', 'max_event_tags', 'max_content_length'].includes(key)) {
            dataType = 'integer';
        } else if (['auth_enabled', 'nip42_auth_required', 'nip40_expiration_enabled'].includes(key)) {
            dataType = 'boolean';
        }

        // Determine category based on key name
        let category = 'general';
        if (key.startsWith('relay_')) {
            category = 'relay';
        } else if (key.startsWith('nip40_')) {
            category = 'expiration';
        } else if (key.startsWith('nip42_') || key.startsWith('auth_')) {
            category = 'authentication';
        } else if (key.startsWith('pow_')) {
            category = 'proof_of_work';
        } else if (key.startsWith('max_')) {
            category = 'limits';
        }

        const configObj = {
            key: key,
            value: newValue,
            data_type: dataType,
            category: category
        };

        // Update cell during save
        actionsCell.textContent = 'SAVING...';
        actionsCell.style.color = 'var(--accent-color)';
        actionsCell.style.cursor = 'not-allowed';
        actionsCell.onclick = null;

        // Send single config update
        await sendConfigUpdateCommand([configObj]);

        // Update the original value on success
        const input = actionsCell.parentElement.cells[1].querySelector('input');
        if (input) {
            input.dataset.originalValue = newValue;
            // Hide SAVE text since value now matches original
            actionsCell.style.color = 'transparent';
            actionsCell.style.cursor = 'default';
            actionsCell.onclick = null;
        }

        actionsCell.textContent = 'SAVED';
        actionsCell.style.color = 'var(--accent-color)';
        setTimeout(() => {
            actionsCell.textContent = 'SAVE';
            // Keep transparent if value matches original
            if (input && input.value === input.dataset.originalValue) {
                actionsCell.style.color = 'transparent';
            }
        }, 2000);

        log(`Successfully saved config: ${key} = ${newValue}`, 'INFO');

    } catch (error) {
        log(`Failed to save individual config ${key}: ${error.message}`, 'ERROR');
        actionsCell.textContent = 'SAVE';
        actionsCell.style.color = 'var(--primary-color)';
        actionsCell.style.cursor = 'pointer';
        actionsCell.onclick = () => saveIndividualConfig(key, actionsCell.parentElement.cells[1].querySelector('input').value, originalValue, actionsCell);
    }
}




// Send config update command using kind 23456 with Administrator API (inner events)
async function sendConfigUpdateCommand(configObjects) {
    try {
        if (!relayPool) {
            throw new Error('SimplePool connection not available');
        }

        console.log(`Sending config_update command with ${configObjects.length} configuration object(s)`);

        // Create command array for config update
        const command_array = ["config_update", configObjects];

        // Encrypt the command array directly using NIP-44
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create single kind 23456 admin event
        const configEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(configEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        console.log(`Config update event signed with ${configObjects.length} object(s)`);

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                console.log(`✅ Config Update Relay ${index} (${url}): Event published successfully`);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('INFO', `Config update relay ${index} publish success`, 'PUBLISH');
                }
            } else {
                console.error(`❌ Config Update Relay ${index} (${url}): Publish failed:`, result.reason);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('ERROR', `Config update relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
                }
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected config update event. Details: ${errorDetails}`);
        }

        console.log(`Config update command sent successfully with ${configObjects.length} configuration object(s)`);

        // Log for testing
        if (typeof logTestEvent === 'function') {
            logTestEvent('SENT', `Config update command: ${configObjects.length} object(s)`, 'CONFIG_UPDATE');
            configObjects.forEach((config, index) => {
                logTestEvent('SENT', `Config ${index + 1}: ${config.key} = ${config.value} (${config.data_type})`, 'CONFIG');
            });
        }

    } catch (error) {
        console.error(`Failed to send config_update command:`, error);
        throw error;
    }
}



// Profile area click handler removed - dropdown moved to sidebar
// Logout and dark mode buttons are now in the sidebar footer

// Initialize relay pubkey container click handler for clipboard copy
const relayPubkeyContainer = document.getElementById('relay-pubkey-container');
if (relayPubkeyContainer) {
    relayPubkeyContainer.addEventListener('click', async function() {
        const relayPubkeyElement = document.getElementById('relay-pubkey');
        if (relayPubkeyElement && relayPubkeyElement.textContent !== 'Loading...') {
            try {
                // Get the full npub (remove all whitespace for continuous string)
                const fullNpub = relayPubkeyElement.textContent.replace(/\s/g, '');

                await navigator.clipboard.writeText(fullNpub);

                // Add copied class for visual feedback
                relayPubkeyContainer.classList.add('copied');

                // Remove the class after animation completes
                setTimeout(() => {
                    relayPubkeyContainer.classList.remove('copied');
                }, 500);

                log('Relay npub copied to clipboard', 'INFO');
            } catch (error) {
                log('Failed to copy relay npub to clipboard', 'ERROR');
            }
        }
    });
}

// Event handlers
fetchConfigBtn.addEventListener('click', function (e) {
    e.preventDefault();
    e.stopPropagation();
    fetchConfiguration().catch(error => {
        console.log('Manual fetch configuration failed: ' + error.message);
    });
});





// ================================
// AUTH RULES MANAGEMENT FUNCTIONS
// ================================

// Global auth rules state
let currentAuthRules = [];
let editingAuthRule = null;

// DOM elements for auth rules
const authRulesSection = document.getElementById('authRulesSection');
const refreshAuthRulesBtn = document.getElementById('refreshAuthRulesBtn');
const authRulesTableContainer = document.getElementById('authRulesTableContainer');
const authRulesTableBody = document.getElementById('authRulesTableBody');
const authRuleFormContainer = document.getElementById('authRuleFormContainer');
const authRuleForm = document.getElementById('authRuleForm');
const authRuleFormTitle = document.getElementById('authRuleFormTitle');
const saveAuthRuleBtn = document.getElementById('saveAuthRuleBtn');
const cancelAuthRuleBtn = document.getElementById('cancelAuthRuleBtn');

// Show auth rules section after login
function showAuthRulesSection() {
    if (authRulesSection) {
        authRulesSection.style.display = 'block';
        updateAuthRulesStatus('ready');
        log('Auth rules section is now available', 'INFO');
    }
}

// Hide auth rules section on logout
function hideAuthRulesSection() {
    if (authRulesSection) {
        authRulesSection.style.display = 'none';

        // Add null checks for all elements
        if (authRulesTableContainer) {
            authRulesTableContainer.style.display = 'none';
        }
        if (authRuleFormContainer) {
            authRuleFormContainer.style.display = 'none';
        }

        currentAuthRules = [];
        editingAuthRule = null;
        log('Auth rules section hidden', 'INFO');
    }
}

// Update auth rules status indicator (removed - no status element)
function updateAuthRulesStatus(status) {
    // Status element removed - no-op
}

// Load auth rules from relay using admin API
async function loadAuthRules() {
    try {
        log('Loading auth rules via admin API...', 'INFO');
        updateAuthRulesStatus('loading');

        if (!isLoggedIn || !userPubkey) {
            throw new Error('Must be logged in to load auth rules');
        }

        if (!relayPool) {
            throw new Error('SimplePool connection not available');
        }

        // Create command array for getting all auth rules
        const command_array = ["auth_query", "all"];

        // Encrypt the command array directly using NIP-44
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create single kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        log('Sending auth rules query to relay...', 'INFO');

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                console.log(`✅ Auth Rules Query Relay ${index} (${url}): Event published successfully`);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('INFO', `Auth rules query relay ${index} publish success`, 'PUBLISH');
                }
            } else {
                console.error(`❌ Auth Rules Query Relay ${index} (${url}): Publish failed:`, result.reason);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('ERROR', `Auth rules query relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
                }
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected auth rules query event. Details: ${errorDetails}`);
        }

        log('Auth rules query sent successfully - waiting for response...', 'INFO');
        updateAuthRulesStatus('loaded');

    } catch (error) {
        log(`Failed to load auth rules: ${error.message}`, 'ERROR');
        updateAuthRulesStatus('error');
        currentAuthRules = [];
        displayAuthRules(currentAuthRules);
    }
}

// Display auth rules in the table
function displayAuthRules(rules) {
    console.log('=== DISPLAY AUTH RULES DEBUG ===');
    console.log('authRulesTableBody element:', authRulesTableBody);
    console.log('Rules to display:', rules);
    console.log('Rules length:', rules ? rules.length : 'undefined');
    console.log('authRulesTableContainer display:', authRulesTableContainer ? authRulesTableContainer.style.display : 'element not found');

    if (!authRulesTableBody) {
        console.log('ERROR: authRulesTableBody element not found');
        return;
    }

    authRulesTableBody.innerHTML = '';
    console.log('Cleared existing table content');

    if (!rules || rules.length === 0) {
        console.log('No rules to display, showing empty message');
        const row = document.createElement('tr');
        row.innerHTML = `<td colspan="6" style="text-align: center; font-style: italic;">No auth rules configured</td>`;
        authRulesTableBody.appendChild(row);
        console.log('Added empty rules message row');
        return;
    }

    console.log(`Displaying ${rules.length} auth rules`);
    rules.forEach((rule, index) => {
        console.log(`Adding rule ${index + 1}:`, rule);
        const row = document.createElement('tr');

        // Convert hex pubkey to npub for display in pattern_value
        let displayPatternValue = rule.pattern_value || rule.rule_target || '-';
        let patternValueLink = displayPatternValue;
        try {
            if (rule.pattern_value && rule.pattern_value.length === 64 && /^[0-9a-fA-F]+$/.test(rule.pattern_value)) {
                const npub = window.NostrTools.nip19.npubEncode(rule.pattern_value);
                displayPatternValue = npub;
                patternValueLink = `<a href="https://njump.me/${npub}" target="_blank" class="npub-link">${npub}</a>`;
            }
        } catch (error) {
            console.log('Failed to encode pattern_value to npub:', error.message);
        }

        row.innerHTML = `
                    <td>${rule.rule_type}</td>
                    <td>${rule.pattern_type || rule.operation || '-'}</td>
                    <td style="font-family: 'Courier New', monospace; font-size: 12px; word-break: break-all; max-width: 200px;">${patternValueLink}</td>
                    <td>${rule.enabled !== false ? 'Active' : 'Inactive'}</td>
                    <td>
                        <div class="inline-buttons">
                            <button onclick="editAuthRule(${index})" style="margin: 2px; padding: 4px 8px; font-size: 12px;">EDIT</button>
                            <button onclick="deleteAuthRule(${index})" style="margin: 2px; padding: 4px 8px; font-size: 12px;">DELETE</button>
                        </div>
                    </td>
                `;
        authRulesTableBody.appendChild(row);
    });

    // Update status display
    console.log(`Total Rules: ${rules.length}, Active Rules: ${rules.filter(r => r.enabled !== false).length}`);

    console.log('=== END DISPLAY AUTH RULES DEBUG ===');
}

// Show auth rules table (automatically called when auth rules are loaded)
function showAuthRulesTable() {
    console.log('=== SHOW AUTH RULES TABLE DEBUG ===');
    console.log('authRulesTableContainer element:', authRulesTableContainer);
    console.log('Current display style:', authRulesTableContainer ? authRulesTableContainer.style.display : 'element not found');

    if (authRulesTableContainer) {
        authRulesTableContainer.style.display = 'block';
        console.log('Set authRulesTableContainer display to block');

        // If we already have cached auth rules, display them immediately
        if (currentAuthRules && currentAuthRules.length >= 0) {
            console.log('Displaying cached auth rules:', currentAuthRules.length, 'rules');
            displayAuthRules(currentAuthRules);
            updateAuthRulesStatus('loaded');
            log(`Auth rules table displayed with ${currentAuthRules.length} cached rules`, 'INFO');
        } else {
            // No cached rules, load from relay
            console.log('No cached auth rules, loading from relay...');
            loadAuthRules();
            log('Auth rules table displayed - loading from relay', 'INFO');
        }
    } else {
        console.log('ERROR: authRulesTableContainer element not found');
    }
    console.log('=== END SHOW AUTH RULES TABLE DEBUG ===');
}

// Show add auth rule form
function showAddAuthRuleForm() {
    if (authRuleFormContainer && authRuleFormTitle) {
        editingAuthRule = null;
        authRuleFormTitle.textContent = 'Add Auth Rule';
        authRuleForm.reset();
        authRuleFormContainer.style.display = 'block';
        log('Opened add auth rule form', 'INFO');
    }
}

// Show edit auth rule form
function editAuthRule(index) {
    if (index < 0 || index >= currentAuthRules.length) return;

    const rule = currentAuthRules[index];
    editingAuthRule = { ...rule, index: index };

    if (authRuleFormTitle && authRuleForm) {
        authRuleFormTitle.textContent = 'Edit Auth Rule';

        // Populate form fields
        document.getElementById('authRuleType').value = rule.rule_type || '';
        document.getElementById('authPatternType').value = rule.pattern_type || rule.operation || '';
        document.getElementById('authPatternValue').value = rule.pattern_value || rule.rule_target || '';
        document.getElementById('authRuleAction').value = rule.action || 'allow';
        document.getElementById('authRuleDescription').value = rule.description || '';

        authRuleFormContainer.style.display = 'block';
        log(`Editing auth rule: ${rule.rule_type} - ${rule.pattern_value || rule.rule_target}`, 'INFO');
    }
}

// Delete auth rule using Administrator API (inner events)
async function deleteAuthRule(index) {
    if (index < 0 || index >= currentAuthRules.length) return;

    const rule = currentAuthRules[index];
    const confirmMsg = `Delete auth rule: ${rule.rule_type} - ${rule.pattern_value || rule.rule_target}?`;

    if (!confirm(confirmMsg)) return;

    try {
        log(`Deleting auth rule: ${rule.rule_type} - ${rule.pattern_value || rule.rule_target}`, 'INFO');

        if (!isLoggedIn || !userPubkey) {
            throw new Error('Must be logged in to delete auth rules');
        }

        if (!relayPool) {
            throw new Error('SimplePool connection not available');
        }

        // Create command array for deleting auth rule
        // Format: ["system_command", "delete_auth_rule", rule_type, pattern_type, pattern_value]
        const rule_type = rule.rule_type;
        const pattern_type = rule.pattern_type || 'pubkey';
        const pattern_value = rule.pattern_value || rule.rule_target;

        const command_array = ["system_command", "delete_auth_rule", rule_type, pattern_type, pattern_value];

        // Encrypt the command array directly using NIP-44
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create single kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        log('Sending delete auth rule command to relay...', 'INFO');

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                console.log(`✅ Delete Auth Rule Relay ${index} (${url}): Event published successfully`);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('INFO', `Delete auth rule relay ${index} publish success`, 'PUBLISH');
                }
            } else {
                console.error(`❌ Delete Auth Rule Relay ${index} (${url}): Publish failed:`, result.reason);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('ERROR', `Delete auth rule relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
                }
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected delete auth rule event. Details: ${errorDetails}`);
        }

        log('Delete auth rule command sent successfully - waiting for response...', 'INFO');

        // Remove from local array immediately for UI responsiveness
        currentAuthRules.splice(index, 1);
        displayAuthRules(currentAuthRules);

    } catch (error) {
        log(`Failed to delete auth rule: ${error.message}`, 'ERROR');
    }
}

// Hide auth rule form
function hideAuthRuleForm() {
    if (authRuleFormContainer) {
        authRuleFormContainer.style.display = 'none';
        editingAuthRule = null;
        log('Auth rule form hidden', 'INFO');
    }
}

// Validate auth rule form
function validateAuthRuleForm() {
    const ruleType = document.getElementById('authRuleType').value;
    const patternType = document.getElementById('authPatternType').value;
    const patternValue = document.getElementById('authPatternValue').value.trim();
    const action = document.getElementById('authRuleAction').value;

    if (!ruleType) {
        alert('Please select a rule type');
        return false;
    }

    if (!patternType) {
        alert('Please select a pattern type');
        return false;
    }

    if (!patternValue) {
        alert('Please enter a pattern value');
        return false;
    }

    if (!action) {
        alert('Please select an action');
        return false;
    }

    // Validate pubkey format for pubkey rules
    if ((ruleType === 'pubkey_whitelist' || ruleType === 'pubkey_blacklist') &&
        patternValue.length !== 64) {
        alert('Pubkey must be exactly 64 hex characters');
        return false;
    }

    // Validate hex format for pubkey rules
    if ((ruleType === 'pubkey_whitelist' || ruleType === 'pubkey_blacklist')) {
        const hexPattern = /^[0-9a-fA-F]+$/;
        if (!hexPattern.test(patternValue)) {
            alert('Pubkey must contain only hex characters (0-9, a-f, A-F)');
            return false;
        }
    }

    return true;
}

// Save auth rule (add or update)
async function saveAuthRule(event) {
    event.preventDefault();

    if (!validateAuthRuleForm()) return;

    try {
        const ruleData = {
            rule_type: document.getElementById('authRuleType').value,
            pattern_type: document.getElementById('authPatternType').value,
            pattern_value: document.getElementById('authPatternValue').value.trim(),
            action: document.getElementById('authRuleAction').value,
            description: document.getElementById('authRuleDescription').value.trim() || null,
            enabled: true
        };

        if (editingAuthRule) {
            log(`Updating auth rule: ${ruleData.rule_type} - ${ruleData.pattern_value}`, 'INFO');

            // TODO: Implement actual rule update via WebSocket kind 23456 event
            // For now, just update local array
            currentAuthRules[editingAuthRule.index] = { ...ruleData, id: editingAuthRule.id || Date.now() };

            log('Auth rule updated (placeholder implementation)', 'INFO');
        } else {
            log(`Adding new auth rule: ${ruleData.rule_type} - ${ruleData.pattern_value}`, 'INFO');

            // TODO: Implement actual rule creation via WebSocket kind 23456 event
            // For now, just add to local array
            currentAuthRules.push({ ...ruleData, id: Date.now() });

            log('Auth rule added (placeholder implementation)', 'INFO');
        }

        displayAuthRules(currentAuthRules);
        hideAuthRuleForm();

    } catch (error) {
        log(`Failed to save auth rule: ${error.message}`, 'ERROR');
    }
}

// Monitoring is now subscription-based - no auto-enable needed
// Monitoring automatically activates when someone subscribes to kind 24567 events
async function autoEnableMonitoring() {
    log('Monitoring system is subscription-based - no manual enable needed', 'INFO');
    log('Subscribe to kind 24567 events to receive real-time monitoring data', 'INFO');
}

// Update existing logout and showMainInterface functions to handle auth rules and NIP-17 DMs
const originalLogout = logout;
logout = async function () {
    hideAuthRulesSection();
    // Clear DM inbox and outbox on logout
    if (dmInbox) {
        dmInbox.innerHTML = '<div class="log-entry">No messages received yet.</div>';
    }
    if (dmOutbox) {
        dmOutbox.value = '';
    }
    await originalLogout();
};

const originalShowMainInterface = showMainInterface;
showMainInterface = function () {
    originalShowMainInterface();
    // Removed showAuthRulesSection() call - visibility now handled by updateAdminSectionsVisibility()
};

// Auth rules event handlers
if (refreshAuthRulesBtn) {
    refreshAuthRulesBtn.addEventListener('click', function (e) {
        e.preventDefault();
        loadAuthRules();
    });
}

if (authRuleForm) {
    authRuleForm.addEventListener('submit', saveAuthRule);
}

if (cancelAuthRuleBtn) {
    cancelAuthRuleBtn.addEventListener('click', function (e) {
        e.preventDefault();
        hideAuthRuleForm();
    });
}

// ================================
// STREAMLINED AUTH RULE FUNCTIONS
// ================================

// Utility function to convert nsec to hex pubkey or npub to hex pubkey
function nsecToHex(input) {
    if (!input || input.trim().length === 0) {
        return null;
    }

    const trimmed = input.trim();

    // If it's already 64-char hex, return as-is
    if (/^[0-9a-fA-F]{64}$/.test(trimmed)) {
        return trimmed;
    }

    // If it starts with nsec1, try to decode
    if (trimmed.startsWith('nsec1')) {
        try {
            if (window.NostrTools && window.NostrTools.nip19 && window.NostrTools.nip19.decode) {
                const decoded = window.NostrTools.nip19.decode(trimmed);
                if (decoded.type === 'nsec') {
                    // Handle different versions of nostr-tools
                    if (typeof decoded.data === 'string') {
                        // v1 style - data is already hex
                        return decoded.data;
                    } else {
                        // v2 style - data is Uint8Array
                        const hexPubkey = Array.from(decoded.data)
                            .map(b => b.toString(16).padStart(2, '0'))
                            .join('');
                        return hexPubkey;
                    }
                }
            }
        } catch (error) {
            console.error('Failed to decode nsec:', error);
            return null;
        }
    }

    // If it starts with npub1, try to decode to hex
    if (trimmed.startsWith('npub1')) {
        try {
            if (window.NostrTools && window.NostrTools.nip19 && window.NostrTools.nip19.decode) {
                const decoded = window.NostrTools.nip19.decode(trimmed);
                if (decoded.type === 'npub') {
                    // Handle different versions of nostr-tools
                    if (typeof decoded.data === 'string') {
                        // v1 style - data is already hex
                        return decoded.data;
                    } else {
                        // v2 style - data is Uint8Array
                        const hexPubkey = Array.from(decoded.data)
                            .map(b => b.toString(16).padStart(2, '0'))
                            .join('');
                        return hexPubkey;
                    }
                }
            }
        } catch (error) {
            console.error('Failed to decode npub:', error);
            return null;
        }
    }

    return null; // Invalid format
}

// Add blacklist rule (updated to use combined input)
function addBlacklistRule() {
    const input = document.getElementById('authRulePubkey');

    if (!input) return;

    const inputValue = input.value.trim();
    if (!inputValue) {
        log('Please enter a pubkey or nsec', 'ERROR');
        return;
    }

    // Convert nsec or npub to hex if needed
    const hexPubkey = nsecToHex(inputValue);
    if (!hexPubkey) {
        log('Invalid pubkey format. Please enter nsec1..., npub1..., or 64-character hex', 'ERROR');
        return;
    }

    // Validate hex length
    if (hexPubkey.length !== 64) {
        log('Invalid pubkey length. Must be exactly 64 characters', 'ERROR');
        return;
    }

    log('Adding to blacklist...', 'INFO');

    // Create auth rule data
    const ruleData = {
        rule_type: 'pubkey_blacklist',
        pattern_type: 'Global',
        pattern_value: hexPubkey,
        action: 'deny'
    };

    // Add to WebSocket queue for processing
    addAuthRuleViaWebSocket(ruleData)
        .then(() => {
            log(`Pubkey ${hexPubkey.substring(0, 16)}... added to blacklist`, 'INFO');
            input.value = '';

            // Refresh auth rules display if visible
            if (authRulesTableContainer && authRulesTableContainer.style.display !== 'none') {
                loadAuthRules();
            }
        })
        .catch(error => {
            log(`Failed to add rule: ${error.message}`, 'ERROR');
        });
}

// Add whitelist rule (updated to use combined input)
function addWhitelistRule() {
    const input = document.getElementById('authRulePubkey');
    const warningDiv = document.getElementById('whitelistWarning');

    if (!input) return;

    const inputValue = input.value.trim();
    if (!inputValue) {
        log('Please enter a pubkey or nsec', 'ERROR');
        return;
    }

    // Convert nsec or npub to hex if needed
    const hexPubkey = nsecToHex(inputValue);
    if (!hexPubkey) {
        log('Invalid pubkey format. Please enter nsec1..., npub1..., or 64-character hex', 'ERROR');
        return;
    }

    // Validate hex length
    if (hexPubkey.length !== 64) {
        log('Invalid pubkey length. Must be exactly 64 characters', 'ERROR');
        return;
    }

    // Show whitelist warning
    if (warningDiv) {
        warningDiv.style.display = 'block';
    }

    log('Adding to whitelist...', 'INFO');

    // Create auth rule data
    const ruleData = {
        rule_type: 'pubkey_whitelist',
        pattern_type: 'Global',
        pattern_value: hexPubkey,
        action: 'allow'
    };

    // Add to WebSocket queue for processing
    addAuthRuleViaWebSocket(ruleData)
        .then(() => {
            log(`Pubkey ${hexPubkey.substring(0, 16)}... added to whitelist`, 'INFO');
            input.value = '';

            // Refresh auth rules display if visible
            if (authRulesTableContainer && authRulesTableContainer.style.display !== 'none') {
                loadAuthRules();
            }
        })
        .catch(error => {
            log(`Failed to add rule: ${error.message}`, 'ERROR');
        });
}

// Add auth rule via SimplePool (kind 23456 event) - FIXED to match working test pattern
async function addAuthRuleViaWebSocket(ruleData) {
    if (!isLoggedIn || !userPubkey) {
        throw new Error('Must be logged in to add auth rules');
    }

    if (!relayPool) {
        throw new Error('SimplePool connection not available');
    }

    try {
        log(`Adding auth rule: ${ruleData.rule_type} - ${ruleData.pattern_value.substring(0, 16)}...`, 'INFO');

        // Map client-side rule types to command array format (matching working tests)
        let commandRuleType, commandPatternType;

        switch (ruleData.rule_type) {
            case 'pubkey_blacklist':
                commandRuleType = 'blacklist';
                commandPatternType = 'pubkey';
                break;
            case 'pubkey_whitelist':
                commandRuleType = 'whitelist';
                commandPatternType = 'pubkey';
                break;
            case 'hash_blacklist':
                commandRuleType = 'blacklist';
                commandPatternType = 'hash';
                break;
            default:
                throw new Error(`Unknown rule type: ${ruleData.rule_type}`);
        }

        // Create command array in the same format as working tests
        // Format: ["blacklist", "pubkey", "abc123..."] or ["whitelist", "pubkey", "def456..."]
        const command_array = [commandRuleType, commandPatternType, ruleData.pattern_value];

        // Encrypt the command array directly using NIP-44
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create single kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // DEBUG: Log the complete event structure being sent
        console.log('=== AUTH RULE EVENT DEBUG (Administrator API) ===');
        console.log('Original Rule Data:', ruleData);
        console.log('Command Array:', command_array);
        console.log('Encrypted Content:', encrypted_content.substring(0, 50) + '...');
        console.log('Auth Event (before signing):', JSON.stringify(authEvent, null, 2));
        console.log('=== END AUTH RULE EVENT DEBUG ===');

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                console.log(`✅ Add Auth Rule Relay ${index} (${url}): Event published successfully`);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('INFO', `Add auth rule relay ${index} publish success`, 'PUBLISH');
                }
            } else {
                console.error(`❌ Add Auth Rule Relay ${index} (${url}): Publish failed:`, result.reason);
                if (typeof logTestEvent === 'function') {
                    logTestEvent('ERROR', `Add auth rule relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
                }
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected add auth rule event. Details: ${errorDetails}`);
        }

        log('Auth rule added successfully', 'INFO');

    } catch (error) {
        log(`Failed to add auth rule: ${error.message}`, 'ERROR');
        throw error;
    }
}

// ================================
// TEST FUNCTIONS FOR ADMIN API
// ================================

// Test event logging function
function logTestEvent(direction, message, type = 'INFO') {
    const testLog = document.getElementById('test-event-log');
    if (!testLog) return;

    const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
    const logEntry = document.createElement('div');
    logEntry.className = 'log-entry';

    const directionColor = direction === 'SENT' ? '#007bff' : '#28a745';
    logEntry.innerHTML = `
                <span class="log-timestamp">${timestamp}</span>
                <span style="color: ${directionColor}; font-weight: bold;">[${direction}]</span>
                <span style="color: #666;">[${type}]</span>
                ${message}
            `;

    testLog.appendChild(logEntry);
    testLog.scrollTop = testLog.scrollHeight;
}

// Test: Get Auth Rules
async function testGetAuthRules() {
    if (!isLoggedIn || !userPubkey) {
        logTestEvent('ERROR', 'Must be logged in to test admin API', 'ERROR');
        return;
    }

    if (!relayPool) {
        logTestEvent('ERROR', 'SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        logTestEvent('INFO', 'Testing Get Auth Rules command...', 'TEST');

        // Create command array for getting auth rules
        const command_array = '["auth_query", "all"]';

        // Encrypt the command content using NIP-44
        const encrypted_content = await encryptForRelay(command_array);
        if (!encrypted_content) {
            throw new Error('Failed to encrypt auth query command');
        }

        // Create kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [
                ["p", getRelayPubkey()]
            ],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        logTestEvent('SENT', `Get Auth Rules event: ${JSON.stringify(signedEvent)}`, 'EVENT');

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                logTestEvent('INFO', `Test Add Blacklist relay ${index} publish success`, 'PUBLISH');
            } else {
                logTestEvent('ERROR', `Test Add Blacklist relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected test add blacklist event. Details: ${errorDetails}`);
        }

        logTestEvent('INFO', 'Get Auth Rules command sent successfully', 'SUCCESS');

    } catch (error) {
        logTestEvent('ERROR', `Get Auth Rules test failed: ${error.message}`, 'ERROR');
    }
}

// Test: Clear All Auth Rules
async function testClearAuthRules() {
    if (!isLoggedIn || !userPubkey) {
        logTestEvent('ERROR', 'Must be logged in to test admin API', 'ERROR');
        return;
    }

    if (!relayPool) {
        logTestEvent('ERROR', 'SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        logTestEvent('INFO', 'Testing Clear All Auth Rules command...', 'TEST');

        // Create command array for clearing auth rules
        const command_array = '["system_command", "clear_all_auth_rules"]';

        // Encrypt the command content using NIP-44
        const encrypted_content = await encryptForRelay(command_array);
        if (!encrypted_content) {
            throw new Error('Failed to encrypt clear auth rules command');
        }

        // Create kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [
                ["p", getRelayPubkey()]
            ],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        logTestEvent('SENT', `Clear Auth Rules event: ${JSON.stringify(signedEvent)}`, 'EVENT');

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                logTestEvent('INFO', `Test Add Whitelist relay ${index} publish success`, 'PUBLISH');
            } else {
                logTestEvent('ERROR', `Test Add Whitelist relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected test add whitelist event. Details: ${errorDetails}`);
        }

        logTestEvent('INFO', 'Clear Auth Rules command sent successfully', 'SUCCESS');

    } catch (error) {
        logTestEvent('ERROR', `Clear Auth Rules test failed: ${error.message}`, 'ERROR');
    }
}

// Test: Add Blacklist
async function testAddBlacklist() {
    const testPubkeyInput = document.getElementById('test-pubkey-input');
    let testPubkey = testPubkeyInput ? testPubkeyInput.value.trim() : '';

    // Use a default test pubkey if none provided
    if (!testPubkey) {
        testPubkey = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
        logTestEvent('INFO', `Using default test pubkey: ${testPubkey}`, 'INFO');
    }

    if (!isLoggedIn || !userPubkey) {
        logTestEvent('ERROR', 'Must be logged in to test admin API', 'ERROR');
        return;
    }

    if (!relayPool) {
        logTestEvent('ERROR', 'SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        logTestEvent('INFO', `Testing Add Blacklist for pubkey: ${testPubkey.substring(0, 16)}...`, 'TEST');

        // Create command array for adding blacklist rule
        const command_array = `["blacklist", "pubkey", "${testPubkey}"]`;

        // Encrypt the command content using NIP-44
        const encrypted_content = await encryptForRelay(command_array);
        if (!encrypted_content) {
            throw new Error('Failed to encrypt blacklist command');
        }

        // Create kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [
                ["p", getRelayPubkey()]
            ],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        logTestEvent('SENT', `Add Blacklist event: ${JSON.stringify(signedEvent)}`, 'EVENT');

        // Publish via SimplePool with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                logTestEvent('INFO', `Test Config Query relay ${index} publish success`, 'PUBLISH');
            } else {
                logTestEvent('ERROR', `Test Config Query relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected test config query event. Details: ${errorDetails}`);
        }

        logTestEvent('INFO', 'Add Blacklist command sent successfully', 'SUCCESS');

    } catch (error) {
        logTestEvent('ERROR', `Add Blacklist test failed: ${error.message}`, 'ERROR');
    }
}

// Test: Add Whitelist
async function testAddWhitelist() {
    const testPubkeyInput = document.getElementById('test-pubkey-input');
    let testPubkey = testPubkeyInput ? testPubkeyInput.value.trim() : '';

    // Use a default test pubkey if none provided
    if (!testPubkey) {
        testPubkey = 'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890';
        logTestEvent('INFO', `Using default test pubkey: ${testPubkey}`, 'INFO');
    }

    if (!isLoggedIn || !userPubkey) {
        logTestEvent('ERROR', 'Must be logged in to test admin API', 'ERROR');
        return;
    }

    if (!relayPool) {
        logTestEvent('ERROR', 'SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        logTestEvent('INFO', `Testing Add Whitelist for pubkey: ${testPubkey.substring(0, 16)}...`, 'TEST');

        // Create command array for adding whitelist rule
        const command_array = `["whitelist", "pubkey", "${testPubkey}"]`;

        // Encrypt the command content using NIP-44
        const encrypted_content = await encryptForRelay(command_array);
        if (!encrypted_content) {
            throw new Error('Failed to encrypt whitelist command');
        }

        // Create kind 23456 admin event
        const authEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [
                ["p", getRelayPubkey()]
            ],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(authEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        logTestEvent('SENT', `Add Whitelist event: ${JSON.stringify(signedEvent)}`, 'EVENT');

        // Publish via SimplePool
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                logTestEvent('INFO', `Test Post Event relay ${index} publish success`, 'PUBLISH');
            } else {
                logTestEvent('ERROR', `Test Post Event relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected test post event. Details: ${errorDetails}`);
        }

        logTestEvent('INFO', 'Add Whitelist command sent successfully', 'SUCCESS');

    } catch (error) {
        logTestEvent('ERROR', `Add Whitelist test failed: ${error.message}`, 'ERROR');
    }
}

// Test: Config Query
async function testConfigQuery() {
    if (!isLoggedIn || !userPubkey) {
        logTestEvent('ERROR', 'Must be logged in to test admin API', 'ERROR');
        return;
    }

    if (!relayPool) {
        logTestEvent('ERROR', 'SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        logTestEvent('INFO', 'Testing Config Query command...', 'TEST');

        // Create command array for getting configuration
        const command_array = '["config_query", "all"]';

        // Encrypt the command content using NIP-44
        const encrypted_content = await encryptForRelay(command_array);
        if (!encrypted_content) {
            throw new Error('Failed to encrypt config query command');
        }

        // Create kind 23456 admin event
        const configEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [
                ["p", getRelayPubkey()]
            ],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(configEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        logTestEvent('SENT', `Config Query event: ${JSON.stringify(signedEvent)}`, 'EVENT');

        // Publish via SimplePool with detailed error diagnostics
        const url = relayUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                logTestEvent('INFO', `Test Config Query relay ${index} publish success`, 'PUBLISH');
            } else {
                logTestEvent('ERROR', `Test Config Query relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected test config query event. Details: ${errorDetails}`);
        }

        logTestEvent('INFO', 'Config Query command sent successfully', 'SUCCESS');

    } catch (error) {
        logTestEvent('ERROR', `Config Query test failed: ${error.message}`, 'ERROR');
    }
}

// Test: Post Basic Event
async function testPostEvent() {
    if (!isLoggedIn || !userPubkey) {
        logTestEvent('ERROR', 'Must be logged in to test event posting', 'ERROR');
        return;
    }

    if (!relayPool) {
        logTestEvent('ERROR', 'SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        logTestEvent('INFO', 'Testing basic event posting...', 'TEST');

        // Create a simple kind 1 text note event
        const testEvent = {
            kind: 1,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [
                ["t", "test"],
                ["client", "c-relay-admin-api"]
            ],
            content: `Test event from C-Relay Admin API at ${new Date().toISOString()}`
        };

        logTestEvent('SENT', `Test event (before signing): ${JSON.stringify(testEvent)}`, 'EVENT');

        // Sign the event using NIP-07
        const signedEvent = await window.nostr.signEvent(testEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        logTestEvent('SENT', `Signed test event: ${JSON.stringify(signedEvent)}`, 'EVENT');

        // Publish via SimplePool to the same relay with detailed error diagnostics
        const url = relayConnectionUrl.value.trim();
        logTestEvent('INFO', `Publishing to relay: ${url}`, 'INFO');

        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes instead of Promise.any
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results for diagnostics
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                logTestEvent('INFO', `Test Post Event relay ${index} publish success`, 'PUBLISH');
            } else {
                logTestEvent('ERROR', `Test Post Event relay ${index} publish failed: ${result.reason?.message || result.reason}`, 'PUBLISH');
            }
        });

        // Throw error if all relays failed
        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected test post event. Details: ${errorDetails}`);
        }

        logTestEvent('INFO', 'Test event published successfully!', 'SUCCESS');
        logTestEvent('INFO', 'Check if the event appears in the subscription above...', 'INFO');

    } catch (error) {
        logTestEvent('ERROR', `Post Event test failed: ${error.message}`, 'ERROR');
        console.error('Post Event test error:', error);
    }
}

// Helper function to encrypt content for relay using NIP-44
async function encryptForRelay(content) {
    try {
        logTestEvent('INFO', `Encrypting content: ${content}`, 'DEBUG');

        // Get the relay public key for encryption
        const relayPubkey = getRelayPubkey();

        // Check if we have access to NIP-44 encryption via nostr-tools
        if (!window.NostrTools || !window.NostrTools.nip44) {
            throw new Error('NIP-44 encryption not available - nostr-tools library missing');
        }

        // Get user's private key for encryption
        // We need to use the NIP-07 extension to get the private key
        if (!window.nostr || !window.nostr.nip44) {
            throw new Error('NIP-44 encryption not available via NIP-07 extension');
        }

        // Use NIP-07 extension's NIP-44 encrypt method
        const encrypted_content = await window.nostr.nip44.encrypt(relayPubkey, content);

        if (!encrypted_content) {
            throw new Error('NIP-44 encryption returned empty result');
        }

        logTestEvent('INFO', `Successfully encrypted content using NIP-44`, 'DEBUG');
        logTestEvent('INFO', `Encrypted content: ${encrypted_content.substring(0, 50)}...`, 'DEBUG');

        return encrypted_content;
    } catch (error) {
        logTestEvent('ERROR', `NIP-44 encryption failed: ${error.message}`, 'ERROR');

        // Fallback: Try using nostr-tools directly if NIP-07 fails
        try {
            logTestEvent('INFO', 'Attempting fallback encryption with nostr-tools...', 'DEBUG');

            if (!window.NostrTools || !window.NostrTools.nip44) {
                throw new Error('nostr-tools NIP-44 not available');
            }

            // We need the user's private key, but we can't get it directly
            // This is a security limitation - we should use NIP-07
            throw new Error('Cannot access private key for direct encryption - use NIP-07 extension');

        } catch (fallbackError) {
            logTestEvent('ERROR', `Fallback encryption failed: ${fallbackError.message}`, 'ERROR');
            return null;
        }
    }
}

// Send NIP-17 Direct Message to relay using NIP-59 layering
async function sendNIP17DM() {
    if (!isLoggedIn || !userPubkey) {
        log('Must be logged in to send DM', 'ERROR');
        return;
    }

    if (!isRelayConnected || !relayPubkey) {
        log('Must be connected to relay to send DM', 'ERROR');
        return;
    }

    const message = dmOutbox.value.trim();
    if (!message) {
        log('Please enter a message to send', 'ERROR');
        return;
    }

    // Capability checks
    if (!window.nostr || !window.nostr.nip44 || !window.nostr.signEvent) {
        log('NIP-17 DMs require a NIP-07 extension with NIP-44 support', 'ERROR');
        alert('NIP-17 DMs require a NIP-07 extension with NIP-44 support. Please install and configure a compatible extension.');
        return;
    }

    if (!window.NostrTools || !window.NostrTools.generateSecretKey || !window.NostrTools.getPublicKey || !window.NostrTools.finalizeEvent) {
        log('NostrTools library not available for ephemeral key operations', 'ERROR');
        alert('NostrTools library not available. Please ensure nostr.bundle.js is loaded.');
        return;
    }

    try {
        log(`Sending NIP-17 DM to relay: ${message.substring(0, 50)}...`, 'INFO');

        // Step 1: Build unsigned rumor (kind 14)
        const rumor = {
            kind: 14,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000), // Canonical time for rumor
            tags: [["p", relayPubkey]],
            content: message
        };
        // NOTE: Rumor remains unsigned per NIP-59

        log('Rumor built (unsigned), creating seal...', 'INFO');

        // Step 2: Create seal (kind 13)
        const seal = {
            kind: 13,
            pubkey: userPubkey,
            created_at: randomNow(), // Randomized to past for metadata protection
            tags: [], // Empty tags per NIP-59
            content: await window.nostr.nip44.encrypt(relayPubkey, JSON.stringify(rumor))
        };

        // Sign seal with long-term key
        const signedSeal = await window.nostr.signEvent(seal);
        if (!signedSeal || !signedSeal.sig) {
            throw new Error('Failed to sign seal event');
        }

        log('Seal created and signed, creating gift wrap...', 'INFO');

        // Step 3: Create gift wrap (kind 1059) with ephemeral key
        const ephemeralPriv = window.NostrTools.generateSecretKey();
        const ephemeralPub = window.NostrTools.getPublicKey(ephemeralPriv);

        const giftWrap = {
            kind: 1059,
            pubkey: ephemeralPub,
            created_at: randomNow(), // Randomized to past for metadata protection
            tags: [["p", relayPubkey]],
            content: await window.NostrTools.nip44.encrypt(
                JSON.stringify(signedSeal),
                window.NostrTools.nip44.getConversationKey(ephemeralPriv, relayPubkey)
            )
        };

        // Sign gift wrap with ephemeral key using finalizeEvent
        const signedGiftWrap = window.NostrTools.finalizeEvent(giftWrap, ephemeralPriv);
        if (!signedGiftWrap || !signedGiftWrap.sig) {
            throw new Error('Failed to sign gift wrap event');
        }

        // DEBUG: Log NIP-17 event details when created
        console.log('=== NIP-17 EVENT CREATED ===');
        console.log('Full event:', JSON.stringify(signedGiftWrap, null, 2));
        console.log('Timestamp:', signedGiftWrap.created_at);
        console.log('Local date time:', new Date(signedGiftWrap.created_at * 1000).toLocaleString());
        console.log('=== END NIP-17 EVENT DEBUG ===');

        log('NIP-17 DM event created and signed with ephemeral key, publishing...', 'INFO');

        // Publish via SimplePool
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedGiftWrap);

        // Use Promise.allSettled to capture per-relay outcomes
        const results = await Promise.allSettled(publishPromises);

        // Log detailed publish results
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                log(`✅ NIP-17 DM published successfully to relay ${index}`, 'INFO');
            } else {
                log(`❌ NIP-17 DM failed on relay ${index}: ${result.reason?.message || result.reason}`, 'ERROR');
            }
        });

        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected NIP-17 DM event. Details: ${errorDetails}`);
        }

        // Clear the outbox and show success
        dmOutbox.value = '';
        log('NIP-17 DM sent successfully', 'INFO');

        // Add to inbox for display
        addMessageToInbox('sent', message, new Date().toLocaleString());

    } catch (error) {
        log(`Failed to send NIP-17 DM: ${error.message}`, 'ERROR');
    }
}

// Add message to inbox display
function addMessageToInbox(direction, message, timestamp, pubkey = null) {
    if (!dmInbox) return;

    const messageDiv = document.createElement('div');
    messageDiv.className = 'log-entry';

    const directionColor = direction === 'sent' ? '#007bff' : '#28a745';

    // Convert newlines to <br> tags for proper HTML display
    const formattedMessage = message.replace(/\n/g, '<br>');

    // Add pubkey display for received messages
    let pubkeyDisplay = '';
    if (pubkey && direction === 'received') {
        try {
            const npub = window.NostrTools.nip19.npubEncode(pubkey);
            pubkeyDisplay = ` <span style="color: #666; font-size: 11px;">(${npub})</span>`;
        } catch (error) {
            console.error('Failed to encode pubkey to npub:', error);
        }
    }

    messageDiv.innerHTML = `
                <span class="log-timestamp">${timestamp}</span>
                <span style="color: ${directionColor}; font-weight: bold;">[${direction.toUpperCase()}]</span>
                <span style="white-space: pre-wrap;">${formattedMessage}${pubkeyDisplay}</span>
            `;

    // Remove the "No messages received yet" placeholder if it exists
    const placeholder = dmInbox.querySelector('.log-entry');
    if (placeholder && placeholder.textContent === 'No messages received yet.') {
        dmInbox.innerHTML = '';
    }

    // Add new message at the top
    dmInbox.insertBefore(messageDiv, dmInbox.firstChild);

    // Limit to last 50 messages
    while (dmInbox.children.length > 50) {
        dmInbox.removeChild(dmInbox.lastChild);
    }
}

// Update relay info in header
function updateRelayInfoInHeader() {
    const relayNameElement = document.getElementById('relay-name');
    const relayPubkeyElement = document.getElementById('relay-pubkey');
    const relayDescriptionElement = document.getElementById('relay-description');

    if (!relayNameElement || !relayPubkeyElement || !relayDescriptionElement) {
        return;
    }

    // Get relay info from NIP-11 data or use defaults
    const relayInfo = getRelayInfo();
    const relayName = relayInfo.name || 'C-Relay';
    const relayDescription = relayInfo.description || 'Nostr Relay';

    // Convert relay pubkey to npub
    let relayNpub = 'Loading...';
    if (relayPubkey) {
        try {
            relayNpub = window.NostrTools.nip19.npubEncode(relayPubkey);
        } catch (error) {
            console.log('Failed to encode relay pubkey to npub:', error.message);
            relayNpub = relayPubkey.substring(0, 16) + '...';
        }
    }

    // Format npub into 3 lines of 21 characters each, with spaces dividing each line into 3 groups of 7 characters
    let formattedNpub = relayNpub;
    if (relayNpub.length === 63) {
        const line1 = relayNpub.substring(0, 7) + ' ' + relayNpub.substring(7, 14) + ' ' + relayNpub.substring(14, 21);
        const line2 = relayNpub.substring(21, 28) + ' ' + relayNpub.substring(28, 35) + ' ' + relayNpub.substring(35, 42);
        const line3 = relayNpub.substring(42, 49) + ' ' + relayNpub.substring(49, 56) + ' ' + relayNpub.substring(56, 63);
        formattedNpub = line1 + '\n' + line2 + '\n' + line3;
    }

    relayNameElement.textContent = relayName;
    relayPubkeyElement.textContent = formattedNpub;
    relayDescriptionElement.textContent = relayDescription;
}

// Global variable to store relay info from NIP-11 or config
let relayInfoData = null;

// Helper function to get relay info from stored data
function getRelayInfo() {
    // Return stored relay info if available, otherwise defaults
    if (relayInfoData) {
        return relayInfoData;
    }

    // Default values
    return {
        name: 'C-Relay',
        description: 'Nostr Relay',
        pubkey: relayPubkey
    };
}

// Update stored relay info when config is loaded
function updateStoredRelayInfo(configData) {
    if (configData && configData.data) {
        // Extract relay info from config data
        const relayName = configData.data.find(item => item.key === 'relay_name')?.value || 'C-Relay';
        const relayDescription = configData.data.find(item => item.key === 'relay_description')?.value || 'Nostr Relay';

        relayInfoData = {
            name: relayName,
            description: relayDescription,
            pubkey: relayPubkey
        };

        // Update header immediately
        updateRelayInfoInHeader();
    }
}

// Helper function to get relay pubkey
function getRelayPubkey() {
    // Use the dynamically fetched relay pubkey if available
    if (relayPubkey) {
        return relayPubkey;
    }

    // No fallback - throw error if relay pubkey not available
    throw new Error('Relay pubkey not available. Please connect to relay first.');
}

// Enhanced SimplePool message handler to capture test responses
function enhancePoolForTesting() {
    // SimplePool handles message parsing automatically, so we just need to
    // ensure our event handlers log appropriately. This is already done
    // in the subscription onevent callback.
    console.log('SimplePool enhanced for testing - automatic message handling enabled');
}

// Generate random test pubkey function
function generateRandomTestKey() {
    // Generate 32 random bytes (64 hex characters) for a valid pubkey
    const randomBytes = new Uint8Array(32);
    crypto.getRandomValues(randomBytes);

    // Convert to hex string
    const hexPubkey = Array.from(randomBytes)
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');

    // Set the generated key in the input field
    const testPubkeyInput = document.getElementById('test-pubkey-input');
    if (testPubkeyInput) {
        testPubkeyInput.value = hexPubkey;
        logTestEvent('INFO', `Generated random test pubkey: ${hexPubkey.substring(0, 16)}...`, 'KEYGEN');
    }

    return hexPubkey;
}

// ================================
// DATABASE STATISTICS FUNCTIONS
// ================================

// Send restart command to restart the relay using Administrator API
async function sendRestartCommand() {
    if (!isLoggedIn || !userPubkey) {
        log('Must be logged in to restart relay', 'ERROR');
        return;
    }

    if (!relayPool) {
        log('SimplePool connection not available', 'ERROR');
        return;
    }

    try {
        log('Sending restart command to relay...', 'INFO');

        // Create command array for restart
        const command_array = ["system_command", "restart"];

        // Encrypt the command array directly using NIP-44
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create single kind 23456 admin event
        const restartEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(restartEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        // Publish via SimplePool
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes
        const results = await Promise.allSettled(publishPromises);

        // Check if any relay accepted the event
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                log(`Restart command published successfully to relay ${index}`, 'INFO');
            } else {
                log(`Restart command failed on relay ${index}: ${result.reason?.message || result.reason}`, 'ERROR');
            }
        });

        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected restart command. Details: ${errorDetails}`);
        }

        log('Restart command sent successfully - relay should restart shortly...', 'INFO');

        // Update connection status to indicate restart is in progress
        updateRelayConnectionStatus('connecting');
        relayConnectionStatus.textContent = 'RESTARTING...';

        // The relay will disconnect and need to be reconnected after restart
        // This will be handled by the WebSocket disconnection event

    } catch (error) {
        log(`Failed to send restart command: ${error.message}`, 'ERROR');
        updateRelayConnectionStatus('error');
    }
}

// Send stats_query command to get database statistics using Administrator API (inner events)
async function sendStatsQuery() {
    if (!isLoggedIn || !userPubkey) {
        log('Must be logged in to query database statistics', 'ERROR');
        updateStatsStatus('error', 'Not logged in');
        return;
    }

    if (!relayPool) {
        log('SimplePool connection not available', 'ERROR');
        updateStatsStatus('error', 'No relay connection');
        return;
    }

    try {
        updateStatsStatus('loading', 'Querying database...');

        // Create command array for stats query
        const command_array = ["stats_query", "all"];

        // Encrypt the command array directly using NIP-44
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create single kind 23456 admin event
        const statsEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(statsEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        log('Sending stats query command...', 'INFO');

        // Publish via SimplePool
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Use Promise.allSettled to capture per-relay outcomes
        const results = await Promise.allSettled(publishPromises);

        // Check if any relay accepted the event
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                log(`Stats query published successfully to relay ${index}`, 'INFO');
            } else {
                log(`Stats query failed on relay ${index}: ${result.reason?.message || result.reason}`, 'ERROR');
            }
        });

        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected stats query event. Details: ${errorDetails}`);
        }

        log('Stats query command sent successfully - waiting for response...', 'INFO');
        updateStatsStatus('waiting', 'Waiting for response...');

    } catch (error) {
        log(`Failed to send stats query: ${error.message}`, 'ERROR');
        updateStatsStatus('error', error.message);
    }
}

// Handle stats_query response and populate tables
function handleStatsQueryResponse(responseData) {
    try {
        log('Processing stats query response...', 'INFO');
        console.log('Stats response data:', responseData);

        if (responseData.query_type !== 'stats_query') {
            log('Ignoring non-stats response', 'WARNING');
            return;
        }

        // Populate overview table
        populateStatsOverview(responseData);

        // Populate event kinds table
        populateStatsKinds(responseData);

        // Populate time-based statistics
        populateStatsTime(responseData);

        // Populate top pubkeys table
        populateStatsPubkeys(responseData);

        updateStatsStatus('loaded');
        log('Database statistics updated successfully', 'INFO');

    } catch (error) {
        log(`Error processing stats response: ${error.message}`, 'ERROR');
        updateStatsStatus('error', 'Failed to process response');
    }
}

// Update statistics display from real-time monitoring event
function updateStatsFromMonitoringEvent(monitoringData) {
    try {

        if (monitoringData.data_type !== 'event_kinds') {
            return;
        }

        // Update total events count and track rate for chart
        if (monitoringData.total_events !== undefined) {
            const currentTotal = monitoringData.total_events;
            updateStatsCell('total-events', currentTotal.toString());
            
            // Calculate new events since last update for chart
            if (previousTotalEvents > 0) {
                const newEvents = currentTotal - previousTotalEvents;
                if (newEvents > 0 && eventRateChart) {
                    console.log(`Adding ${newEvents} new events to rate chart (${currentTotal} - ${previousTotalEvents})`);
                    eventRateChart.addValue(newEvents);
                }
            }
            
            // Update previous total for next calculation
            previousTotalEvents = currentTotal;
        }

        // Update event kinds table with real-time data
        if (monitoringData.kinds && Array.isArray(monitoringData.kinds)) {
            populateStatsKindsFromMonitoring(monitoringData.kinds, monitoringData.total_events);
        }

    } catch (error) {
        log(`Error updating stats from monitoring event: ${error.message}`, 'ERROR');
    }
}

// Update statistics display from time_stats monitoring event
function updateStatsFromTimeMonitoringEvent(monitoringData) {
    try {
        if (monitoringData.data_type !== 'time_stats') {
            return;
        }

        // Update time-based statistics table with real-time data
        if (monitoringData.periods && Array.isArray(monitoringData.periods)) {
            // Use the existing populateStatsTime function which expects the nested time_stats object
            const timeStats = { last_24h: 0, last_7d: 0, last_30d: 0 };

            // Extract values from periods array
            monitoringData.periods.forEach(period => {
                if (period.period === 'last_24h') timeStats.last_24h = period.count;
                else if (period.period === 'last_7d') timeStats.last_7d = period.count;
                else if (period.period === 'last_30d') timeStats.last_30d = period.count;
            });

            populateStatsTime({ time_stats: timeStats });
        }

    } catch (error) {
        log(`Error updating time stats from monitoring event: ${error.message}`, 'ERROR');
    }
}

// Update statistics display from top_pubkeys monitoring event
function updateStatsFromTopPubkeysMonitoringEvent(monitoringData) {
    try {
        if (monitoringData.data_type !== 'top_pubkeys') {
            return;
        }

        // Update top pubkeys table with real-time data
        if (monitoringData.pubkeys && Array.isArray(monitoringData.pubkeys)) {
            // Pass total_events from monitoring data to the function
            populateStatsPubkeysFromMonitoring(monitoringData.pubkeys, monitoringData.total_events || 0);
        }

    } catch (error) {
        log(`Error updating top pubkeys from monitoring event: ${error.message}`, 'ERROR');
    }
}


// Update statistics display from subscription_details monitoring event
function updateStatsFromSubscriptionDetailsMonitoringEvent(monitoringData) {
    try {
        // DEBUG: Log every subscription_details event that arrives at the webpage
        // console.log('subscription_details', JSON.stringify(monitoringData, null, 2));
        console.log('subscription_details decoded:', monitoringData);

        if (monitoringData.data_type !== 'subscription_details') {
            return;
        }

        // Update subscription details table with real-time data
        if (monitoringData.data && Array.isArray(monitoringData.data.subscriptions)) {
            populateSubscriptionDetailsTable(monitoringData.data.subscriptions);
        }

    } catch (error) {
        log(`Error updating subscription details from monitoring event: ${error.message}`, 'ERROR');
    }
}

// Update statistics display from CPU metrics monitoring event
function updateStatsFromCpuMonitoringEvent(monitoringData) {
    try {
        if (monitoringData.data_type !== 'cpu_metrics') {
            return;
        }

        // Update CPU metrics in the database statistics table
        if (monitoringData.process_id !== undefined) {
            updateStatsCell('process-id', monitoringData.process_id.toString());
        }

        if (monitoringData.memory_usage_mb !== undefined) {
            updateStatsCell('memory-usage', monitoringData.memory_usage_mb.toFixed(1) + ' MB');
        }

        if (monitoringData.current_cpu_core !== undefined) {
            updateStatsCell('cpu-core', 'Core ' + monitoringData.current_cpu_core);
        }

        // Calculate CPU usage percentage if we have the data
        if (monitoringData.process_cpu_time !== undefined && monitoringData.system_cpu_time !== undefined) {
            // For now, just show the raw process CPU time (simplified)
            // In a real implementation, you'd calculate deltas over time
            updateStatsCell('cpu-usage', monitoringData.process_cpu_time + ' ticks');
        }

    } catch (error) {
        log(`Error updating CPU metrics from monitoring event: ${error.message}`, 'ERROR');
    }
}

// Populate event kinds table from monitoring data
function populateStatsKindsFromMonitoring(kindsData, totalEvents) {
    const tableBody = document.getElementById('stats-kinds-table-body');
    if (!tableBody) return;

    tableBody.innerHTML = '';

    if (kindsData.length === 0) {
        const row = document.createElement('tr');
        row.innerHTML = '<td colspan="3" style="text-align: center; font-style: italic;">No event data</td>';
        tableBody.appendChild(row);
        return;
    }

    kindsData.forEach(kind => {
        const row = document.createElement('tr');
        const percentage = totalEvents > 0 ? ((kind.count / totalEvents) * 100).toFixed(1) : '0.0';
        row.innerHTML = `
                    <td>${kind.kind}</td>
                    <td>${kind.count}</td>
                    <td>${percentage}%</td>
                `;
        tableBody.appendChild(row);
    });
}

// Populate database overview table
function populateStatsOverview(data) {
    if (!data) return;

    // Update individual cells with flash animation for changed values
    updateStatsCell('db-size', data.database_size_bytes ? formatFileSize(data.database_size_bytes) : '-');
    updateStatsCell('total-events', data.total_events || '-');
    updateStatsCell('oldest-event', data.database_created_at ? formatTimestamp(data.database_created_at) : '-');
    updateStatsCell('newest-event', data.latest_event_at ? formatTimestamp(data.latest_event_at) : '-');
}

// Populate event kinds distribution table
function populateStatsKinds(data) {
    const tableBody = document.getElementById('stats-kinds-table-body');
    if (!tableBody || !data.event_kinds) return;

    tableBody.innerHTML = '';

    if (data.event_kinds.length === 0) {
        const row = document.createElement('tr');
        row.innerHTML = '<td colspan="3" style="text-align: center; font-style: italic;">No event data</td>';
        tableBody.appendChild(row);
        return;
    }

    data.event_kinds.forEach(kind => {
        const row = document.createElement('tr');
        row.innerHTML = `
                    <td>${kind.kind}</td>
                    <td>${kind.count}</td>
                    <td>${kind.percentage}%</td>
                `;
        tableBody.appendChild(row);
    });
}

// Populate time-based statistics table
function populateStatsTime(data) {
    if (!data) return;

    // Access the nested time_stats object from backend response
    const timeStats = data.time_stats || {};

    // Update cells with flash animation for changed values
    updateStatsCell('events-24h', timeStats.last_24h || '0');
    updateStatsCell('events-7d', timeStats.last_7d || '0');
    updateStatsCell('events-30d', timeStats.last_30d || '0');
}

// Populate top pubkeys table
function populateStatsPubkeys(data) {
    const tableBody = document.getElementById('stats-pubkeys-table-body');
    if (!tableBody || !data.top_pubkeys) return;

    tableBody.innerHTML = '';

    if (data.top_pubkeys.length === 0) {
        const row = document.createElement('tr');
        row.innerHTML = '<td colspan="4" style="text-align: center; font-style: italic;">No pubkey data</td>';
        tableBody.appendChild(row);
        return;
    }

    data.top_pubkeys.forEach((pubkey, index) => {
        const row = document.createElement('tr');
        // Convert hex pubkey to npub for display
        let displayPubkey = pubkey.pubkey || '-';
        let npubLink = displayPubkey;
        try {
            if (pubkey.pubkey && pubkey.pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey.pubkey)) {
                const npub = window.NostrTools.nip19.npubEncode(pubkey.pubkey);
                displayPubkey = npub;
                npubLink = `<a href="https://njump.me/${npub}" target="_blank" class="npub-link">${npub}</a>`;
            }
        } catch (error) {
            console.log('Failed to encode pubkey to npub:', error.message);
        }
        row.innerHTML = `
                    <td>${index + 1}</td>
                    <td style="font-family: 'Courier New', monospace; font-size: 12px; word-break: break-all;">${npubLink}</td>
                    <td>${pubkey.event_count}</td>
                    <td>${pubkey.percentage}%</td>
                `;
        tableBody.appendChild(row);
    });
}

// Populate top pubkeys table from monitoring data
function populateStatsPubkeysFromMonitoring(pubkeysData, totalEvents) {
    const tableBody = document.getElementById('stats-pubkeys-table-body');
    if (!tableBody || !pubkeysData || !Array.isArray(pubkeysData)) return;

    tableBody.innerHTML = '';

    if (pubkeysData.length === 0) {
        const row = document.createElement('tr');
        row.innerHTML = '<td colspan="4" style="text-align: center; font-style: italic;">No pubkey data</td>';
        tableBody.appendChild(row);
        return;
    }

    pubkeysData.forEach((pubkey, index) => {
        const row = document.createElement('tr');
        // Convert hex pubkey to npub for display
        let displayPubkey = pubkey.pubkey || '-';
        let npubLink = displayPubkey;
        try {
            if (pubkey.pubkey && pubkey.pubkey.length === 64 && /^[0-9a-fA-F]+$/.test(pubkey.pubkey)) {
                const npub = window.NostrTools.nip19.npubEncode(pubkey.pubkey);
                displayPubkey = npub;
                npubLink = `<a href="https://njump.me/${npub}" target="_blank" class="npub-link">${npub}</a>`;
            }
        } catch (error) {
            console.log('Failed to encode pubkey to npub:', error.message);
        }

        // Calculate percentage using totalEvents parameter
        const percentage = totalEvents > 0 ? ((pubkey.event_count / totalEvents) * 100).toFixed(1) : '0.0';

        row.innerHTML = `
                    <td>${index + 1}</td>
                    <td style="font-family: 'Courier New', monospace; font-size: 12px; word-break: break-all;">${npubLink}</td>
                    <td>${pubkey.event_count}</td>
                    <td>${percentage}%</td>
                `;
        tableBody.appendChild(row);
    });
}

// Populate subscription details table from monitoring data
function populateSubscriptionDetailsTable(subscriptionsData) {
    const tableBody = document.getElementById('subscription-details-table-body');
    if (!tableBody || !subscriptionsData || !Array.isArray(subscriptionsData)) return;

    // Store current expand/collapse state before rebuilding
    const expandedGroups = new Set();
    const headerRows = tableBody.querySelectorAll('.subscription-group-header');
    headerRows.forEach(header => {
        const wsiPointer = header.getAttribute('data-wsi-pointer');
        const isExpanded = header.getAttribute('data-expanded') === 'true';
        if (isExpanded) {
            expandedGroups.add(wsiPointer);
        }
    });

    tableBody.innerHTML = '';

    if (subscriptionsData.length === 0) {
        const row = document.createElement('tr');
        row.innerHTML = '<td colspan="4" style="text-align: center; font-style: italic;">No active subscriptions</td>';
        tableBody.appendChild(row);
        return;
    }

    // Sort subscriptions by wsi_pointer to group them together
    subscriptionsData.sort((a, b) => {
        const wsiA = a.wsi_pointer || '';
        const wsiB = b.wsi_pointer || '';
        return wsiA.localeCompare(wsiB);
    });

    // Group subscriptions by wsi_pointer
    const groupedSubscriptions = {};
    subscriptionsData.forEach(sub => {
        const wsiKey = sub.wsi_pointer || 'N/A';
        if (!groupedSubscriptions[wsiKey]) {
            groupedSubscriptions[wsiKey] = [];
        }
        groupedSubscriptions[wsiKey].push(sub);
    });

    // Create rows for each group
    Object.entries(groupedSubscriptions).forEach(([wsiPointer, subscriptions]) => {
        // Calculate group summary
        const subCount = subscriptions.length;
        const now = Math.floor(Date.now() / 1000);
        const oldestDuration = Math.max(...subscriptions.map(s => now - s.created_at));
        const oldestDurationStr = formatDuration(oldestDuration);

        // Calculate total query stats for this connection
        const totalQueries = subscriptions.reduce((sum, s) => sum + (s.db_queries_executed || 0), 0);
        const totalRows = subscriptions.reduce((sum, s) => sum + (s.db_rows_returned || 0), 0);
        const avgQueryRate = subscriptions.length > 0 ? (subscriptions[0].query_rate_per_min || 0) : 0;
        const clientIp = subscriptions.length > 0 ? (subscriptions[0].client_ip || 'unknown') : 'unknown';

        // Create header row (summary)
        const headerRow = document.createElement('tr');
        headerRow.className = 'subscription-group-header';
        headerRow.setAttribute('data-wsi-pointer', wsiPointer);
        const wasExpanded = expandedGroups.has(wsiPointer);
        headerRow.setAttribute('data-expanded', wasExpanded ? 'true' : 'false');

        headerRow.innerHTML = `
            <td colspan="4" style="padding: 8px;">
                <span class="expand-icon" style="display: inline-block; width: 20px; transition: transform 0.2s;">▶</span>
                <strong style="font-family: 'Courier New', monospace; font-size: 12px;">IP: ${clientIp}</strong>
                <span style="color: #666; margin-left: 10px; font-size: 11px;">
                    WS: ${wsiPointer} |
                    Subs: ${subCount} |
                    Queries: ${totalQueries.toLocaleString()} |
                    Rows: ${totalRows.toLocaleString()} |
                    Rate: ${avgQueryRate.toFixed(1)} q/min |
                    Duration: ${oldestDurationStr}
                </span>
            </td>
        `;

        // Add click handler to toggle expansion
        headerRow.addEventListener('click', () => toggleSubscriptionGroup(wsiPointer));

        tableBody.appendChild(headerRow);

        // Create detail rows (initially hidden)
        subscriptions.forEach((subscription, index) => {
            const detailRow = document.createElement('tr');
            detailRow.className = 'subscription-detail-row';
            detailRow.setAttribute('data-wsi-group', wsiPointer);
            detailRow.style.display = 'none';

            // Calculate duration
            const duration = now - subscription.created_at;
            const durationStr = formatDuration(duration);

            // Format filters
            let filtersDisplay = 'None';
            if (subscription.filters && subscription.filters.length > 0) {
                const filterDetails = [];
                subscription.filters.forEach((filter) => {
                    const parts = [];

                    if (filter.kinds && Array.isArray(filter.kinds) && filter.kinds.length > 0) {
                        parts.push(`kinds:[${filter.kinds.join(',')}]`);
                    }

                    if (filter.authors && Array.isArray(filter.authors) && filter.authors.length > 0) {
                        const authorCount = filter.authors.length;
                        if (authorCount === 1) {
                            const shortPubkey = filter.authors[0].substring(0, 8) + '...';
                            parts.push(`authors:[${shortPubkey}]`);
                        } else {
                            parts.push(`authors:[${authorCount} pubkeys]`);
                        }
                    }

                    if (filter.ids && Array.isArray(filter.ids) && filter.ids.length > 0) {
                        const idCount = filter.ids.length;
                        parts.push(`ids:[${idCount} event${idCount > 1 ? 's' : ''}]`);
                    }

                    const timeParts = [];
                    if (filter.since && filter.since > 0) {
                        const sinceDate = new Date(filter.since * 1000).toLocaleString();
                        timeParts.push(`since:${sinceDate}`);
                    }
                    if (filter.until && filter.until > 0) {
                        const untilDate = new Date(filter.until * 1000).toLocaleString();
                        timeParts.push(`until:${untilDate}`);
                    }
                    if (timeParts.length > 0) {
                        parts.push(timeParts.join(', '));
                    }

                    if (filter.limit && filter.limit > 0) {
                        parts.push(`limit:${filter.limit}`);
                    }

                    if (filter.tag_filters && Array.isArray(filter.tag_filters) && filter.tag_filters.length > 0) {
                        parts.push(`tags:[${filter.tag_filters.length} filter${filter.tag_filters.length > 1 ? 's' : ''}]`);
                    }

                    if (parts.length > 0) {
                        filterDetails.push(parts.join(', '));
                    } else {
                        filterDetails.push('empty filter');
                    }
                });

                filtersDisplay = filterDetails.join(' | ');
            }

            detailRow.innerHTML = `
                <td class="subscription-detail-prefix">└─</td>
                <td class="subscription-detail-id">${subscription.id || 'N/A'}</td>
                <td class="subscription-detail-duration">${durationStr}</td>
                <td class="subscription-detail-filters">${filtersDisplay}</td>
            `;

            tableBody.appendChild(detailRow);

            // Restore expand/collapse state after adding all rows
            if (wasExpanded) {
                const detailRows = tableBody.querySelectorAll(`.subscription-detail-row[data-wsi-group="${wsiPointer}"]`);
                detailRows.forEach(row => row.style.display = 'table-row');
                const expandIcon = headerRow.querySelector('.expand-icon');
                if (expandIcon) {
                    expandIcon.textContent = '▼';
                    expandIcon.style.transform = 'rotate(90deg)';
                }
            }
        });
    });
}

// Toggle function for expanding/collapsing groups
function toggleSubscriptionGroup(wsiPointer) {
    const headerRow = document.querySelector(`.subscription-group-header[data-wsi-pointer="${wsiPointer}"]`);
    const detailRows = document.querySelectorAll(`.subscription-detail-row[data-wsi-group="${wsiPointer}"]`);
    const expandIcon = headerRow.querySelector('.expand-icon');

    const isExpanded = headerRow.getAttribute('data-expanded') === 'true';

    if (isExpanded) {
        // Collapse
        detailRows.forEach(row => row.style.display = 'none');
        expandIcon.textContent = '▶';
        expandIcon.style.transform = 'rotate(0deg)';
        headerRow.setAttribute('data-expanded', 'false');
    } else {
        // Expand
        detailRows.forEach(row => row.style.display = 'table-row');
        expandIcon.textContent = '▼';
        expandIcon.style.transform = 'rotate(90deg)';
        headerRow.setAttribute('data-expanded', 'true');
    }
}

// Helper function to format duration in human-readable format
function formatDuration(seconds) {
    if (seconds < 60) return `${seconds}s`;
    if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
    if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
    return `${Math.floor(seconds / 86400)}d ${Math.floor((seconds % 86400) / 3600)}h`;
}

// Update statistics status indicator (disabled - status display removed)
function updateStatsStatus(status, message = '') {
    // Status display has been removed from the UI
    return;
}

// Utility function to format file size
function formatFileSize(bytes) {
    if (!bytes || bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

// Utility function to format timestamp
function formatTimestamp(timestamp) {
    if (!timestamp) return '-';
    const date = new Date(timestamp * 1000);
    return date.toLocaleString();
}

// Update statistics cell with flash animation if value changed
function updateStatsCell(cellId, newValue) {
    const cell = document.getElementById(cellId);
    if (!cell) return;

    const currentValue = cell.textContent;
    cell.textContent = newValue;

    // Flash if value changed
    if (currentValue !== newValue && currentValue !== '-') {
        cell.classList.add('flash-value');
        setTimeout(() => {
            cell.classList.remove('flash-value');
        }, 500);
    }
}

// Start auto-refreshing database statistics every 10 seconds
function startStatsAutoRefresh() {
    // DISABLED - Using real-time monitoring events instead of polling
    // This function is kept for backward compatibility but no longer starts auto-refresh
    log('Database statistics auto-refresh DISABLED - using real-time monitoring events', 'INFO');
}

// Stop auto-refreshing database statistics
function stopStatsAutoRefresh() {
    if (statsAutoRefreshInterval) {
        clearInterval(statsAutoRefreshInterval);
        statsAutoRefreshInterval = null;
    }
    if (countdownInterval) {
        clearInterval(countdownInterval);
        countdownInterval = null;
    }
    // Reset countdown display
    updateCountdownDisplay();
    log('Database statistics auto-refresh stopped', 'INFO');
}

// Update countdown display in refresh button
function updateCountdownDisplay() {
    const refreshBtn = document.getElementById('refresh-stats-btn');
    if (!refreshBtn) return;

    // DISABLED - No countdown display when using real-time monitoring
    // Show empty button text
    refreshBtn.textContent = '';
}

// Flash refresh button red on successful refresh
function flashRefreshButton() {
    const refreshBtn = document.getElementById('refresh-stats-btn');
    if (!refreshBtn) return;

    // DISABLED - No flashing when using real-time monitoring
    // This function is kept for backward compatibility
}

// Event handlers for test buttons
document.addEventListener('DOMContentLoaded', () => {
    // Test button event handlers
    const testGetAuthRulesBtn = document.getElementById('test-get-auth-rules-btn');
    const testClearAuthRulesBtn = document.getElementById('test-clear-auth-rules-btn');
    const testAddBlacklistBtn = document.getElementById('test-add-blacklist-btn');
    const testAddWhitelistBtn = document.getElementById('test-add-whitelist-btn');
    const testConfigQueryBtn = document.getElementById('test-config-query-btn');
    const testPostEventBtn = document.getElementById('test-post-event-btn');
    const clearTestLogBtn = document.getElementById('clear-test-log-btn');
    const generateTestKeyBtn = document.getElementById('generate-test-key-btn');

    if (testGetAuthRulesBtn) {
        testGetAuthRulesBtn.addEventListener('click', testGetAuthRules);
    }

    if (testClearAuthRulesBtn) {
        testClearAuthRulesBtn.addEventListener('click', testClearAuthRules);
    }

    if (testAddBlacklistBtn) {
        testAddBlacklistBtn.addEventListener('click', testAddBlacklist);
    }

    if (testAddWhitelistBtn) {
        testAddWhitelistBtn.addEventListener('click', testAddWhitelist);
    }

    if (testConfigQueryBtn) {
        testConfigQueryBtn.addEventListener('click', testConfigQuery);
    }

    if (testPostEventBtn) {
        testPostEventBtn.addEventListener('click', testPostEvent);
    }

    if (clearTestLogBtn) {
        clearTestLogBtn.addEventListener('click', () => {
            const testLog = document.getElementById('test-event-log');
            if (testLog) {
                testLog.innerHTML = '<div class="log-entry"><span class="log-timestamp">SYSTEM:</span> Test log cleared.</div>';
            }
        });
    }

    if (generateTestKeyBtn) {
        generateTestKeyBtn.addEventListener('click', generateRandomTestKey);
    }

    // Show test input section when needed
    const testInputSection = document.getElementById('test-input-section');
    if (testInputSection) {
        testInputSection.style.display = 'block';
    }

    // Database statistics event handlers
    const refreshStatsBtn = document.getElementById('refresh-stats-btn');
    if (refreshStatsBtn) {
        refreshStatsBtn.addEventListener('click', sendStatsQuery);
    }

    // Subscription details section is always visible when authenticated

    // NIP-17 DM event handlers
    if (sendDmBtn) {
        sendDmBtn.addEventListener('click', sendNIP17DM);
    }

    // SQL Query event handlers
    const executeSqlBtn = document.getElementById('execute-sql-btn');
    const clearSqlBtn = document.getElementById('clear-sql-btn');
    const clearHistoryBtn = document.getElementById('clear-history-btn');

    if (executeSqlBtn) {
        executeSqlBtn.addEventListener('click', executeSqlQuery);
    }

    if (clearSqlBtn) {
        clearSqlBtn.addEventListener('click', clearSqlQuery);
    }

    if (clearHistoryBtn) {
        clearHistoryBtn.addEventListener('click', clearQueryHistory);
    }
});


// Dark mode functionality
function toggleDarkMode() {
    const body = document.body;
    const isDarkMode = body.classList.contains('dark-mode');

    if (isDarkMode) {
        body.classList.remove('dark-mode');
        localStorage.setItem('darkMode', 'false');
        updateDarkModeButton(false);
        log('Switched to light mode', 'INFO');
    } else {
        body.classList.add('dark-mode');
        localStorage.setItem('darkMode', 'true');
        updateDarkModeButton(true);
        log('Switched to dark mode', 'INFO');
    }
}

function updateDarkModeButton(isDarkMode) {
    const navDarkModeBtn = document.getElementById('nav-dark-mode-btn');
    if (navDarkModeBtn) {
        navDarkModeBtn.textContent = isDarkMode ? 'LIGHT MODE' : 'DARK MODE';
    }
}

function initializeDarkMode() {
    const savedDarkMode = localStorage.getItem('darkMode');
    const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
    const shouldBeDark = savedDarkMode === 'true' || (savedDarkMode === null && prefersDark);

    if (shouldBeDark) {
        document.body.classList.add('dark-mode');
        updateDarkModeButton(true);
    } else {
        updateDarkModeButton(false);
    }
}

// Side navigation functions
function toggleSideNav() {
    const sideNav = document.getElementById('side-nav');
    const overlay = document.getElementById('side-nav-overlay');

    if (sideNavOpen) {
        sideNav.classList.remove('open');
        overlay.classList.remove('show');
        sideNavOpen = false;
    } else {
        sideNav.classList.add('open');
        overlay.classList.add('show');
        sideNavOpen = true;
    }
}

function closeSideNav() {
    const sideNav = document.getElementById('side-nav');
    const overlay = document.getElementById('side-nav-overlay');

    sideNav.classList.remove('open');
    overlay.classList.remove('show');
    sideNavOpen = false;
}

function switchPage(pageName) {
    // Update current page
    currentPage = pageName;

    // Update navigation active state
    const navItems = document.querySelectorAll('.nav-item');
    navItems.forEach(item => {
        item.classList.remove('active');
        if (item.getAttribute('data-page') === pageName) {
            item.classList.add('active');
        }
    });

    // Hide all sections
        const sections = [
            'databaseStatisticsSection',
            'subscriptionDetailsSection',
            'div_config',
            'authRulesSection',
            'relayEventsSection',
            'nip17DMSection',
            'sqlQuerySection'
        ];

    sections.forEach(sectionId => {
        const section = document.getElementById(sectionId);
        if (section) {
            section.style.display = 'none';
        }
    });

    // Show selected section
    const pageMap = {
        'statistics': 'databaseStatisticsSection',
        'subscriptions': 'subscriptionDetailsSection',
        'configuration': 'div_config',
        'authorization': 'authRulesSection',
        'relay-events': 'relayEventsSection',
        'dm': 'nip17DMSection',
        'database': 'sqlQuerySection'
    };

    const targetSectionId = pageMap[pageName];
    if (targetSectionId) {
        const targetSection = document.getElementById(targetSectionId);
        if (targetSection) {
            targetSection.style.display = 'block';
        }
    }

    // Special handling for configuration page - ensure config-display is visible and refresh data
    if (pageName === 'configuration') {
        const configDisplay = document.getElementById('config-display');
        if (configDisplay) {
            configDisplay.classList.remove('hidden');
        }
        // Always refresh configuration data when navigating to config page
        fetchConfiguration().catch(error => {
            console.log('Failed to refresh configuration on page switch: ' + error.message);
        });
    }

    // Close side navigation
    closeSideNav();

    log(`Switched to page: ${pageName}`, 'INFO');
}

// Initialize the app
document.addEventListener('DOMContentLoaded', () => {
    console.log('C-Relay Admin API interface loaded');

    // Initialize dark mode
    initializeDarkMode();

    // Initialize sidebar button text
    const navDarkModeBtn = document.getElementById('nav-dark-mode-btn');
    if (navDarkModeBtn) {
        navDarkModeBtn.textContent = document.body.classList.contains('dark-mode') ? 'LIGHT MODE' : 'DARK MODE';
    }

    // Start RELAY letter animation
    startRelayAnimation();

    // Initialize real-time event rate chart
    setTimeout(() => {
        initializeEventRateChart();
    }, 1000); // Delay to ensure text_graph.js is loaded

    // Initialize side navigation
    initializeSideNavigation();

    // Ensure admin sections are hidden by default on page load
    updateAdminSectionsVisibility();

    setTimeout(() => {
        initializeApp();
        // Enhance SimplePool for testing after initialization
        setTimeout(enhancePoolForTesting, 2000);
    }, 100);
});

// Initialize side navigation event handlers
function initializeSideNavigation() {
    // Header title click handler
    const headerTitle = document.getElementById('header-title');
    if (headerTitle) {
        headerTitle.addEventListener('click', toggleSideNav);
    }

    // Overlay click handler
    const overlay = document.getElementById('side-nav-overlay');
    if (overlay) {
        overlay.addEventListener('click', closeSideNav);
    }

    // Navigation item click handlers
    const navItems = document.querySelectorAll('.nav-item');
    navItems.forEach(item => {
        item.addEventListener('click', (e) => {
            const pageName = e.target.getAttribute('data-page');
            if (pageName) {
                switchPage(pageName);
            }
        });
    });

    // Footer button handlers
    const navDarkModeBtn = document.getElementById('nav-dark-mode-btn');
    const navLogoutBtn = document.getElementById('nav-logout-btn');

    if (navDarkModeBtn) {
        navDarkModeBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            toggleDarkMode();
            // Update button text after toggle
            setTimeout(() => {
                navDarkModeBtn.textContent = document.body.classList.contains('dark-mode') ? 'LIGHT MODE' : 'DARK MODE';
            }, 10);
            closeSideNav();
        });
    }

    if (navLogoutBtn) {
        navLogoutBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            logout();
            closeSideNav();
        });
    }

    // Set initial page
    switchPage(currentPage);
}

// ================================
// SQL QUERY FUNCTIONS
// ================================

// Predefined query templates
const SQL_QUERY_TEMPLATES = {
  recent_events: "SELECT id, pubkey, created_at, kind, substr(content, 1, 50) as content FROM events ORDER BY created_at DESC LIMIT 20",
  event_stats: "SELECT * FROM event_stats",
  subscriptions: "SELECT * FROM active_subscriptions_log ORDER BY created_at DESC",
  top_pubkeys: "SELECT * FROM top_pubkeys_view",
  event_kinds: "SELECT * FROM event_kinds_view ORDER BY count DESC",
  time_stats: "SELECT 'total' as period, COUNT(*) as total_events, COUNT(DISTINCT pubkey) as unique_pubkeys, MIN(created_at) as oldest_event, MAX(created_at) as newest_event FROM events UNION ALL SELECT '24h' as period, COUNT(*) as total_events, COUNT(DISTINCT pubkey) as unique_pubkeys, MIN(created_at) as oldest_event, MAX(created_at) as newest_event FROM events WHERE created_at >= (strftime('%s', 'now') - 86400) UNION ALL SELECT '7d' as period, COUNT(*) as total_events, COUNT(DISTINCT pubkey) as unique_pubkeys, MIN(created_at) as oldest_event, MAX(created_at) as newest_event FROM events WHERE created_at >= (strftime('%s', 'now') - 604800) UNION ALL SELECT '30d' as period, COUNT(*) as total_events, COUNT(DISTINCT pubkey) as unique_pubkeys, MIN(created_at) as oldest_event, MAX(created_at) as newest_event FROM events WHERE created_at >= (strftime('%s', 'now') - 2592000)"
};

// Query history management (localStorage)
const QUERY_HISTORY_KEY = 'c_relay_sql_history';
const MAX_HISTORY_ITEMS = 20;

// Load query history from localStorage
function loadQueryHistory() {
  try {
    const history = localStorage.getItem(QUERY_HISTORY_KEY);
    return history ? JSON.parse(history) : [];
  } catch (e) {
    console.error('Failed to load query history:', e);
    return [];
  }
}

// Save query to history
function saveQueryToHistory(query) {
  if (!query || query.trim().length === 0) return;

  try {
    let history = loadQueryHistory();

    // Remove duplicate if exists
    history = history.filter(q => q !== query);

    // Add to beginning
    history.unshift(query);

    // Limit size
    if (history.length > MAX_HISTORY_ITEMS) {
      history = history.slice(0, MAX_HISTORY_ITEMS);
    }

    localStorage.setItem(QUERY_HISTORY_KEY, JSON.stringify(history));
    updateQueryDropdown();
  } catch (e) {
    console.error('Failed to save query history:', e);
  }
}

// Clear query history
function clearQueryHistory() {
  if (confirm('Clear all query history?')) {
    localStorage.removeItem(QUERY_HISTORY_KEY);
    updateQueryDropdown();
  }
}

// Update dropdown with history
function updateQueryDropdown() {
  const historyGroup = document.getElementById('history-group');
  if (!historyGroup) return;

  // Clear existing history options
  historyGroup.innerHTML = '';

  const history = loadQueryHistory();
  if (history.length === 0) {
    const option = document.createElement('option');
    option.value = '';
    option.textContent = '(no history)';
    option.disabled = true;
    historyGroup.appendChild(option);
    return;
  }

  history.forEach((query, index) => {
    const option = document.createElement('option');
    option.value = `history_${index}`;
    // Truncate long queries for display
    const displayQuery = query.length > 60 ? query.substring(0, 60) + '...' : query;
    option.textContent = displayQuery;
    option.dataset.query = query;
    historyGroup.appendChild(option);
  });
}

// Load selected query from dropdown
function loadSelectedQuery() {
  const dropdown = document.getElementById('query-dropdown');
  const selectedValue = dropdown.value;

  if (!selectedValue) return;

  let query = '';

  // Check if it's a template
  if (SQL_QUERY_TEMPLATES[selectedValue]) {
    query = SQL_QUERY_TEMPLATES[selectedValue];
  }
  // Check if it's from history
  else if (selectedValue.startsWith('history_')) {
    const selectedOption = dropdown.options[dropdown.selectedIndex];
    query = selectedOption.dataset.query;
  }

  if (query) {
    document.getElementById('sql-input').value = query;
  }

  // Reset dropdown to placeholder
  dropdown.value = '';
}

// Clear the SQL query input
function clearSqlQuery() {
  document.getElementById('sql-input').value = '';
  document.getElementById('query-info').innerHTML = '';
  document.getElementById('query-table').innerHTML = '';
}

// Execute SQL query via admin API
async function executeSqlQuery() {
  const query = document.getElementById('sql-input').value;
  if (!query.trim()) {
    log('Please enter a SQL query', 'ERROR');
    document.getElementById('query-info').innerHTML = '<div class="error-message">❌ Please enter a SQL query</div>';
    return;
  }

  try {
    // Show loading state
    document.getElementById('query-info').innerHTML = '<div class="loading">Executing query...</div>';
    document.getElementById('query-table').innerHTML = '';

    // Save to history (before execution, so it's saved even if query fails)
    saveQueryToHistory(query.trim());

    // Send query as kind 23456 admin command
    const command = ["sql_query", query];
    const requestEvent = await sendAdminCommand(command);

    // Store query info for when response arrives
    if (requestEvent && requestEvent.id) {
      pendingSqlQueries.set(requestEvent.id, {
        query: query,
        timestamp: Date.now()
      });
    }

    // Note: Response will be handled by the event listener
    // which will call displaySqlQueryResults() when response arrives
  } catch (error) {
    log('Failed to execute query: ' + error.message, 'ERROR');
    document.getElementById('query-info').innerHTML = '<div class="error-message">❌ Failed to execute query: ' + error.message + '</div>';
  }
}

// Helper function to send admin commands (kind 23456 events)
async function sendAdminCommand(commandArray) {
  if (!isLoggedIn || !userPubkey) {
    throw new Error('Must be logged in to send admin commands');
  }

  if (!relayPool) {
    throw new Error('SimplePool connection not available');
  }

  try {
    log(`Sending admin command: ${JSON.stringify(commandArray)}`, 'INFO');

    // Encrypt the command array directly using NIP-44
    const encrypted_content = await encryptForRelay(JSON.stringify(commandArray));
    if (!encrypted_content) {
      throw new Error('Failed to encrypt command array');
    }

    // Create single kind 23456 admin event
    const adminEvent = {
      kind: 23456,
      pubkey: userPubkey,
      created_at: Math.floor(Date.now() / 1000),
      tags: [["p", getRelayPubkey()]],
      content: encrypted_content
    };

    // Sign the event
    const signedEvent = await window.nostr.signEvent(adminEvent);
    if (!signedEvent || !signedEvent.sig) {
      throw new Error('Event signing failed');
    }

    // Publish via SimplePool with detailed error diagnostics
    const url = relayConnectionUrl.value.trim();
    const publishPromises = relayPool.publish([url], signedEvent);

    // Use Promise.allSettled to capture per-relay outcomes
    const results = await Promise.allSettled(publishPromises);

    // Log detailed publish results for diagnostics
    let successCount = 0;
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        successCount++;
        log(`✅ Admin command published successfully to relay ${index}`, 'INFO');
      } else {
        log(`❌ Admin command failed on relay ${index}: ${result.reason?.message || result.reason}`, 'ERROR');
      }
    });

    if (successCount === 0) {
      const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
      throw new Error(`All relays rejected admin command event. Details: ${errorDetails}`);
    }

    log('Admin command sent successfully', 'INFO');
    return signedEvent; // Return the signed event for request ID tracking

  } catch (error) {
    log(`Failed to send admin command: ${error.message}`, 'ERROR');
    throw error;
  }
}

// Display SQL query results
function displaySqlQueryResults(response) {
  const infoDiv = document.getElementById('query-info');
  const tableDiv = document.getElementById('query-table');

  if (response.status === 'error' || response.error) {
    infoDiv.innerHTML = `<div class="error-message">❌ ${response.error || 'Query failed'}</div>`;
    tableDiv.innerHTML = '';
    return;
  }

  // Show query info with request ID for debugging
  const rowCount = response.row_count || 0;
  const execTime = response.execution_time_ms || 0;
  const requestId = response.request_id ? response.request_id.substring(0, 8) + '...' : 'unknown';
  infoDiv.innerHTML = `
    <div class="query-info-success">
      <span>✅ Query executed successfully</span>
      <span>Rows: ${rowCount}</span>
      <span>Execution Time: ${execTime}ms</span>
      <span class="request-id" title="${response.request_id || ''}">Request: ${requestId}</span>
    </div>
  `;

  // Build results table
  if (response.rows && response.rows.length > 0) {
    let html = '<table class="sql-results-table"><thead><tr>';
    response.columns.forEach(col => {
      html += `<th>${escapeHtml(col)}</th>`;
    });
    html += '</tr></thead><tbody>';

    response.rows.forEach(row => {
      html += '<tr>';
      row.forEach(cell => {
        const cellValue = cell === null ? '<em>NULL</em>' : escapeHtml(String(cell));
        html += `<td>${cellValue}</td>`;
      });
      html += '</tr>';
    });

    html += '</tbody></table>';
    tableDiv.innerHTML = html;
  } else {
    tableDiv.innerHTML = '<p class="no-results">No results returned</p>';
  }
}

// Handle SQL query response (called by event listener)
function handleSqlQueryResponse(response) {
  console.log('=== HANDLING SQL QUERY RESPONSE ===');
  console.log('Response:', response);

  // Always display SQL query results when received
  displaySqlQueryResults(response);

  // Clean up any pending queries
  if (response.request_id && pendingSqlQueries.has(response.request_id)) {
    pendingSqlQueries.delete(response.request_id);
  }
}

// Helper function to escape HTML
function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

// Initialize query history on page load
document.addEventListener('DOMContentLoaded', function() {
  updateQueryDropdown();
});

// RELAY letter animation function
function startRelayAnimation() {
    const letters = document.querySelectorAll('.relay-letter');
    let currentIndex = 0;

    function animateLetter() {
        // Remove underline from all letters first
        letters.forEach(letter => letter.classList.remove('underlined'));

        // Add underline to current letter
        if (letters[currentIndex]) {
            letters[currentIndex].classList.add('underlined');
        }

        // Move to next letter
        currentIndex++;

        // If we've gone through all letters, remove all underlines and wait 4000ms then restart
        if (currentIndex > letters.length) {
            // Remove all underlines before the pause
            letters.forEach(letter => letter.classList.remove('underlined'));
            setTimeout(() => {
                currentIndex = 0;
                animateLetter();
            }, 4000);
        } else {
            // Otherwise, continue to next letter after 200ms
            setTimeout(animateLetter, 100);
        }
    }

    // Start the animation
    animateLetter();
}

// ================================
// CONFIG TOGGLE BUTTON COMPONENT
// ================================

// Global registry for config toggle buttons
const configToggleButtons = new Map();

// ConfigToggleButton class for tri-state boolean config toggles
class ConfigToggleButton {
    constructor(configKey, container, options = {}) {
        this.configKey = configKey;
        this.container = container;
        this.state = 'false'; // Start in false state by default
        this.pendingValue = null;
        this.options = {
            dataType: 'boolean',
            category: 'monitoring',
            ...options
        };

        this.render();
        this.attachEventListeners();

        // Register this button instance
        configToggleButtons.set(configKey, this);
    }

    render() {
        console.log('=== RENDERING CONFIG TOGGLE BUTTON ===');
        console.log('Config key:', this.configKey);
        console.log('Container:', this.container);

        // Create button element
        this.button = document.createElement('button');
        this.button.className = 'config-toggle-btn';
        this.button.setAttribute('data-config-key', this.configKey);
        this.button.setAttribute('data-state', this.state);
        this.button.setAttribute('title', `Toggle ${this.configKey}`);
        this.updateIcon();

        console.log('Button element created:', this.button);
        console.log('Container before append:', this.container);
        console.log('Container children before:', this.container.children.length);

        this.container.appendChild(this.button);

        console.log('Container children after:', this.container.children.length);
        console.log('Button in DOM:', document.contains(this.button));
    }

    updateIcon() {
        const icons = {
            'true': 'I',
            'false': '0',
            'indeterminate': '⟳'
        };
        this.button.textContent = icons[this.state] || '?';
    }

    setState(newState) {
        if (['true', 'false', 'indeterminate'].includes(newState)) {
            this.state = newState;
            this.button.setAttribute('data-state', newState);
            this.updateIcon();
        }
    }

    async toggle() {
        console.log('=== TOGGLE BUTTON CLICKED ===');
        console.log('Current state:', this.state);
        console.log('Button element:', this.button);

        if (this.state === 'indeterminate') {
            console.log('Ignoring toggle - currently indeterminate');
            return; // Don't toggle while pending
        }

        // Toggle between true and false
        const newValue = this.state === 'true' ? 'false' : 'true';
        this.pendingValue = newValue;

        console.log('Sending toggle command:', newValue);

        // Set to indeterminate while waiting
        this.setState('indeterminate');

        // Create config object
        const configObj = {
            key: this.configKey,
            value: newValue,
            data_type: this.options.dataType,
            category: this.options.category
        };

        console.log('Config object:', configObj);

        try {
            // Send config update command
            console.log('Sending config update command...');
            await sendConfigUpdateCommand([configObj]);
            console.log('Config update command sent successfully');
            log(`Config toggle sent: ${this.configKey} = ${newValue}`, 'INFO');
        } catch (error) {
            console.log('Config update command failed:', error);
            log(`Failed to send config toggle: ${error.message}`, 'ERROR');
            // Revert to previous state on error
            this.setState('false');
            this.pendingValue = null;
        }
    }

    handleResponse(success, actualValue) {
        console.log('=== HANDLE RESPONSE ===');
        console.log('Success:', success);
        console.log('Actual value:', actualValue);
        console.log('Pending value:', this.pendingValue);

        if (success) {
            console.log('Success - setting to actual server value:', actualValue);
            this.setState(actualValue);
        } else {
            console.log('Failed - reverting to false state');
            // Failed - revert to false state
            this.setState('false');
        }
        this.pendingValue = null;
        console.log('Pending value cleared');
    }

    attachEventListeners() {
        this.button.addEventListener('click', () => this.toggle());
    }
}

// Helper function to get a registered toggle button
function getConfigToggleButton(configKey) {
    return configToggleButtons.get(configKey);
}

// Monitoring is now subscription-based - no toggle button needed
// Monitoring automatically activates when someone subscribes to kind 24567 events
function initializeMonitoringToggleButton() {
    console.log('=== MONITORING IS NOW SUBSCRIPTION-BASED ===');
    console.log('No toggle button needed - monitoring activates automatically when subscribing to kind 24567');
    log('Monitoring system is subscription-based - no manual toggle required', 'INFO');
    return null;
}

// Monitoring is subscription-based - no toggle button response handling needed
const originalHandleConfigUpdateResponse = handleConfigUpdateResponse;
handleConfigUpdateResponse = function(responseData) {
    console.log('=== CONFIG UPDATE RESPONSE HANDLER ===');
    console.log('Response data:', responseData);

    // Call original handler
    originalHandleConfigUpdateResponse(responseData);

    // Monitoring is now subscription-based - no toggle buttons to update
    console.log('Monitoring system is subscription-based - no toggle buttons to handle');
};

// Monitoring is now subscription-based - no toggle buttons needed
function initializeToggleButtonsFromConfig(configData) {
    console.log('=== MONITORING IS SUBSCRIPTION-BASED ===');
    console.log('No toggle buttons needed - monitoring activates automatically when subscribing to kind 24567');
    log('Monitoring system initialized - subscription-based activation ready', 'INFO');
}

// ================================
// RELAY EVENTS FUNCTIONS
// ================================


// Handle received relay events
function handleRelayEventReceived(event) {
    console.log('Handling relay event:', event.kind, event);

    switch (event.kind) {
        case 0:
            populateKind0Form(event);
            break;
        case 10050:
            populateKind10050Form(event);
            break;
        case 10002:
            populateKind10002Form(event);
            break;
        default:
            console.log('Unknown relay event kind:', event.kind);
    }
}

// Populate Kind 0 form (User Metadata)
function populateKind0Form(event) {
    try {
        const metadata = JSON.parse(event.content);
        console.log('Populating Kind 0 form with:', metadata);

        // Update form fields
        const nameField = document.getElementById('kind0-name');
        const aboutField = document.getElementById('kind0-about');
        const pictureField = document.getElementById('kind0-picture');
        const bannerField = document.getElementById('kind0-banner');
        const nip05Field = document.getElementById('kind0-nip05');
        const websiteField = document.getElementById('kind0-website');

        if (nameField) nameField.value = metadata.name || '';
        if (aboutField) aboutField.value = metadata.about || '';
        if (pictureField) pictureField.value = metadata.picture || '';
        if (bannerField) bannerField.value = metadata.banner || '';
        if (nip05Field) nip05Field.value = metadata.nip05 || '';
        if (websiteField) websiteField.value = metadata.website || '';

        showStatus('kind0-status', 'Metadata loaded from relay', 'success');

    } catch (error) {
        console.error('Error populating Kind 0 form:', error);
        showStatus('kind0-status', 'Error loading metadata', 'error');
    }
}

// Populate Kind 10050 form (DM Relay List)
function populateKind10050Form(event) {
    try {
        console.log('Populating Kind 10050 form with tags:', event.tags);

        // Extract relay URLs from "relay" tags
        const relayUrls = event.tags
            .filter(tag => tag[0] === 'relay' && tag[1])
            .map(tag => tag[1]);

        const relaysField = document.getElementById('kind10050-relays');
        if (relaysField) {
            relaysField.value = relayUrls.join('\n');
        }

        showStatus('kind10050-status', 'DM relay list loaded from relay', 'success');

    } catch (error) {
        console.error('Error populating Kind 10050 form:', error);
        showStatus('kind10050-status', 'Error loading DM relay list', 'error');
    }
}

// Populate Kind 10002 form (Relay List)
function populateKind10002Form(event) {
    try {
        console.log('Populating Kind 10002 form with tags:', event.tags);

        // Clear existing entries
        const container = document.getElementById('kind10002-relay-entries');
        if (container) {
            container.innerHTML = '';
        }

        // Extract relay entries from "r" tags
        event.tags.forEach(tag => {
            if (tag[0] === 'r' && tag[1]) {
                const url = tag[1];
                const marker = tag[2] || 'read'; // Default to read if no marker
                const read = marker.includes('read');
                const write = marker.includes('write');

                addRelayEntry(url, read, write);
            }
        });

        showStatus('kind10002-status', 'Relay list loaded from relay', 'success');

    } catch (error) {
        console.error('Error populating Kind 10002 form:', error);
        showStatus('kind10002-status', 'Error loading relay list', 'error');
    }
}

// Submit Kind 0 event
async function submitKind0Event() {
    try {
        showStatus('kind0-status', 'Submitting metadata...', 'info');

        // Collect form data
        const metadata = {
            name: document.getElementById('kind0-name').value.trim(),
            about: document.getElementById('kind0-about').value.trim(),
            picture: document.getElementById('kind0-picture').value.trim(),
            banner: document.getElementById('kind0-banner').value.trim(),
            nip05: document.getElementById('kind0-nip05').value.trim(),
            website: document.getElementById('kind0-website').value.trim()
        };

        // Remove empty fields
        Object.keys(metadata).forEach(key => {
            if (!metadata[key]) delete metadata[key];
        });

        // Validate required fields
        if (!metadata.name) {
            showStatus('kind0-status', 'Name is required', 'error');
            return;
        }

        await sendCreateRelayEventCommand(0, metadata);
        showStatus('kind0-status', 'Metadata updated successfully', 'success');

    } catch (error) {
        console.error('Error submitting Kind 0 event:', error);
        showStatus('kind0-status', 'Error updating metadata: ' + error.message, 'error');
    }
}

// Submit Kind 10050 event
async function submitKind10050Event() {
    try {
        showStatus('kind10050-status', 'Submitting DM relay list...', 'info');

        // Parse textarea content
        const relaysText = document.getElementById('kind10050-relays').value.trim();
        const relays = relaysText.split('\n')
            .map(url => url.trim())
            .filter(url => url.length > 0)
            .filter(url => isValidRelayUrl(url));

        if (relays.length === 0) {
            showStatus('kind10050-status', 'At least one valid relay URL is required', 'error');
            return;
        }

        await sendCreateRelayEventCommand(10050, { relays });
        showStatus('kind10050-status', 'DM relay list updated successfully', 'success');

    } catch (error) {
        console.error('Error submitting Kind 10050 event:', error);
        showStatus('kind10050-status', 'Error updating DM relay list: ' + error.message, 'error');
    }
}

// Submit Kind 10002 event
async function submitKind10002Event() {
    try {
        showStatus('kind10002-status', 'Submitting relay list...', 'info');

        // Collect relay entries
        const relays = [];
        const entries = document.querySelectorAll('.relay-entry');

        entries.forEach(entry => {
            const url = entry.querySelector('.relay-url').value.trim();
            const read = entry.querySelector('.relay-read').checked;
            const write = entry.querySelector('.relay-write').checked;

            if (url && isValidRelayUrl(url)) {
                relays.push({
                    url: url,
                    read: read,
                    write: write
                });
            }
        });

        if (relays.length === 0) {
            showStatus('kind10002-status', 'At least one valid relay entry is required', 'error');
            return;
        }

        await sendCreateRelayEventCommand(10002, { relays });
        showStatus('kind10002-status', 'Relay list updated successfully', 'success');

    } catch (error) {
        console.error('Error submitting Kind 10002 event:', error);
        showStatus('kind10002-status', 'Error updating relay list: ' + error.message, 'error');
    }
}

// Send create_relay_event command
async function sendCreateRelayEventCommand(kind, eventData) {
    if (!isLoggedIn || !userPubkey) {
        throw new Error('Must be logged in to create relay events');
    }

    if (!relayPool) {
        throw new Error('SimplePool connection not available');
    }

    try {
        console.log(`Sending create_relay_event command for kind ${kind}...`);

        // Create command array
        const command_array = ["create_relay_event", kind, eventData];

        // Encrypt the command array
        const encrypted_content = await encryptForRelay(JSON.stringify(command_array));
        if (!encrypted_content) {
            throw new Error('Failed to encrypt command array');
        }

        // Create kind 23456 admin event
        const adminEvent = {
            kind: 23456,
            pubkey: userPubkey,
            created_at: Math.floor(Date.now() / 1000),
            tags: [["p", getRelayPubkey()]],
            content: encrypted_content
        };

        // Sign the event
        const signedEvent = await window.nostr.signEvent(adminEvent);
        if (!signedEvent || !signedEvent.sig) {
            throw new Error('Event signing failed');
        }

        // Publish via SimplePool
        const url = relayConnectionUrl.value.trim();
        const publishPromises = relayPool.publish([url], signedEvent);

        // Wait for publish results
        const results = await Promise.allSettled(publishPromises);
        let successCount = 0;
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                successCount++;
                console.log(`✅ Relay event published successfully to relay ${index}`);
            } else {
                console.error(`❌ Relay event failed on relay ${index}:`, result.reason);
            }
        });

        if (successCount === 0) {
            const errorDetails = results.map((r, i) => `Relay ${i}: ${r.reason?.message || r.reason}`).join('; ');
            throw new Error(`All relays rejected relay event. Details: ${errorDetails}`);
        }

        console.log(`Relay event command sent successfully for kind ${kind}`);

    } catch (error) {
        console.error(`Failed to send create_relay_event command for kind ${kind}:`, error);
        throw error;
    }
}

// Validation helpers
function isValidUrl(url) {
    try {
        new URL(url);
        return true;
    } catch {
        return false;
    }
}

function isValidRelayUrl(url) {
    if (!isValidUrl(url)) return false;
    return url.startsWith('ws://') || url.startsWith('wss://');
}

// UI helpers
function showStatus(elementId, message, type = 'info') {
    const element = document.getElementById(elementId);
    if (!element) return;

    // Remove emojis from message
    const cleanMessage = message.replace(/[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]/gu, '');

    element.textContent = cleanMessage;
    element.className = 'status-message';
    element.style.display = 'block'; // Ensure it's visible

    // Add type-specific styling
    switch (type) {
        case 'success':
            element.style.color = 'var(--accent-color)';
            break;
        case 'error':
            element.style.color = '#ff0000';
            break;
        case 'info':
        default:
            element.style.color = 'var(--primary-color)';
            break;
    }

    // Auto-hide after 5 seconds
    setTimeout(() => {
        element.style.display = 'none';
    }, 5000);
}

function addRelayEntry(url = '', read = true, write = true) {
    const container = document.getElementById('kind10002-relay-entries');
    if (!container) return;

    const entryDiv = document.createElement('div');
    entryDiv.className = 'relay-entry';
    entryDiv.innerHTML = `
        <div class="form-group" style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
            <input type="url" class="relay-url" placeholder="wss://relay.example.com" value="${url}" style="flex: 1; min-width: 300px; pointer-events: auto; cursor: text;">
            <label style="display: flex; align-items: center; gap: 5px; white-space: nowrap;">
                <input type="checkbox" class="relay-read" ${read ? 'checked' : ''}>
                Read
            </label>
            <label style="display: flex; align-items: center; gap: 5px; white-space: nowrap;">
                <input type="checkbox" class="relay-write" ${write ? 'checked' : ''}>
                Write
            </label>
            <button type="button" onclick="removeRelayEntry(this)" style="padding: 4px 8px; font-size: 12px; white-space: nowrap;">Remove</button>
        </div>
    `;

    container.appendChild(entryDiv);
}

function removeRelayEntry(button) {
    const entry = button.closest('.relay-entry');
    if (entry) {
        entry.remove();
    }
}

// Initialize toggle button after DOM is ready
document.addEventListener('DOMContentLoaded', function() {
    console.log('=== DOM CONTENT LOADED - INITIALIZING TOGGLE BUTTON ===');

    // Initialize the monitoring toggle button
    setTimeout(() => {
        console.log('=== SETTIMEOUT CALLBACK - CALLING initializeMonitoringToggleButton ===');
        initializeMonitoringToggleButton();
    }, 500); // Small delay to ensure DOM is fully ready

    // Initialize relay events functionality
    initializeRelayEvents();
});

// Initialize relay events functionality
function initializeRelayEvents() {
    console.log('Initializing relay events functionality...');

    // Set up event handlers for relay events page
    const submitKind0Btn = document.getElementById('submit-kind0-btn');
    const submitKind10050Btn = document.getElementById('submit-kind10050-btn');
    const submitKind10002Btn = document.getElementById('submit-kind10002-btn');
    const addRelayEntryBtn = document.getElementById('add-relay-entry-btn');

    if (submitKind0Btn) {
        submitKind0Btn.addEventListener('click', submitKind0Event);
    }

    if (submitKind10050Btn) {
        submitKind10050Btn.addEventListener('click', submitKind10050Event);
    }

    if (submitKind10002Btn) {
        submitKind10002Btn.addEventListener('click', submitKind10002Event);
    }

    if (addRelayEntryBtn) {
        addRelayEntryBtn.addEventListener('click', () => addRelayEntry());
    }

    // Add one empty relay entry by default for Kind 10002
    const kind10002Container = document.getElementById('kind10002-relay-entries');
    if (kind10002Container && kind10002Container.children.length === 0) {
        addRelayEntry(); // Add one empty entry to start
        console.log('Added initial empty relay entry for Kind 10002');
    }

    console.log('Relay events functionality initialized');
}