document.addEventListener('DOMContentLoaded', () => {
  let apiKey = localStorage.getItem('apiKey') || '';
  let ws = null;
  const pendingRequests = new Map();
  let responseTimeout = null;
  let terminal = null;
  let fitAddon = null;
  let memoryMeter = null;
  let cpuMeter = null;
  let currentPage = 1;
  let totalResults = 0;
  const resultsPerPage = 10;
  let modListCurrentPage = 1;
  let modListSearchQuery = '';
  let allProperties = {};
  let sftpCredentials = null;
  let isSftpOnline = false;
  let hasAttemptedSftpConnect = false;
  const filteredSettings = [
    'bug-report-link',
    'query.port',
    'rcon.password',
    'region-file-compression',
    'rcon.port',
    'server-port',
    'level-type',
    'enable-rcon',
    'enable-status'
  ];

  const sections = document.querySelectorAll('.section-bg');

  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry, index) => {
      if (entry.isIntersecting) {
        entry.target.style.transform = 'translateY(0)';
        entry.target.style.opacity = '1';
        entry.target.style.transitionDelay = `${index * 0.1}s`;
      }
    });
  }, { threshold: 0.1 });

  sections.forEach(section => {
    section.style.transform = 'translateY(30px)';
    section.style.opacity = '0';
    section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out';
    observer.observe(section);
  });

  function throttle(fn, wait) {
    let lastTime = 0;
    return function (...args) {
      const now = Date.now();
      if (now - lastTime >= wait) {
        fn.apply(this, args);
        lastTime = now;
      }
    };
  }

  // Hamburger Menu Toggle
  const hamburger = document.querySelector('.hamburger');
  const mobileNav = document.querySelector('[data-mobile-nav]');
  const navLinks = mobileNav.querySelectorAll('a');

  // Debounce function to prevent rapid clicks
  function debounce(fn, wait) {
    let timeout;
    return function (...args) {
      clearTimeout(timeout);
      timeout = setTimeout(() => fn.apply(this, args), wait);
    };
  }

  hamburger.addEventListener('click', debounce(() => {
    mobileNav.classList.toggle('active');
    hamburger.classList.toggle('active');
  }, 100));

  navLinks.forEach(link => {
    link.addEventListener('click', () => {
      mobileNav.classList.remove('active');
      hamburger.classList.remove('active');
    });
  });

  document.addEventListener('click', (e) => {
    if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) {
      mobileNav.classList.remove('active');
      hamburger.classList.remove('active');
    }
  });

  const elements = {
    loginPage: document.getElementById('loginPage'),
    loginApiKey: document.getElementById('loginApiKey'),
    loginBtn: document.getElementById('loginBtn'),
    loginError: document.getElementById('loginError'),
    authControls: document.getElementById('authControls'),
    apiKeyInput: document.getElementById('apiKey'),
    user: document.getElementById('user'),
    serverStatus: document.getElementById('serverStatus'),
    memoryPercent: document.getElementById('memoryPercent'),
    cpuPercent: document.getElementById('cpuPercent'),
    keyExpiry: document.getElementById('keyExpiry'),
    playerList: document.getElementById('playerList'),
    modList: document.getElementById('modList'),
    logUrl: document.getElementById('logUrl'),
    websiteUrl: document.getElementById('websiteUrl'),
    mapUrl: document.getElementById('mapUrl'),
    myLink: document.getElementById('myLink'),
    geyserLink: document.getElementById('geyserLink'),
    sftpLink: document.getElementById('sftpLink'),
    holesailHash: document.getElementById('holesailHash'),
    geyserHash: document.getElementById('geyserHash'),
    sftpHash: document.getElementById('sftpHash'),
    modResults: document.getElementById('modResults'),
    consoleOutput: document.getElementById('consoleOutput'),
    consoleInput: document.getElementById('consoleInput'),
    dockerLogsTerminal: document.getElementById('dockerLogsTerminal'),
    mainContent: document.getElementById('mainContent'),
    notificationContainer: document.getElementById('notificationContainer'),
    generateMyLinkBtn: document.getElementById('generateMyLinkBtn'),
    generateGeyserLinkBtn: document.getElementById('generateGeyserLinkBtn'),
    generateSftpLinkBtn: document.getElementById('generateSftpLinkBtn'),
    pagination: document.getElementById('pagination'),
    modSearch: document.getElementById('modSearch'),
    closeSearchBtn: document.getElementById('closeSearchBtn'),
    tellModal: document.getElementById('tellModal'),
    tellPlayerName: document.getElementById('tellPlayerName'),
    tellMessage: document.getElementById('tellMessage'),
    tellForm: document.getElementById('tellForm'),
    giveModal: document.getElementById('giveModal'),
    givePlayerName: document.getElementById('givePlayerName'),
    loadoutSelect: document.getElementById('loadoutSelect'),
    customGiveFields: document.getElementById('customGiveFields'),
    giveForm: document.getElementById('giveForm'),
    addItemBtn: document.getElementById('addItemBtn'),
    itemList: document.getElementById('itemList'),
    editPropertiesBtn: document.getElementById('editPropertiesBtn'),
    editPropertiesModal: document.getElementById('editPropertiesModal'),
    propertiesFields: document.getElementById('propertiesFields'),
    editPropertiesForm: document.getElementById('editPropertiesForm'),
    updateModsBtn: document.getElementById('updateModsBtn'),
    updateModsModal: document.getElementById('updateModsModal'),
    updateModsOutput: document.getElementById('updateModsOutput'),
    closeUpdateModsBtn: document.getElementById('closeUpdateModsBtn'),
    stopBtn: document.getElementById('stopBtn'),
    restartBtn: document.getElementById('restartBtn'),
    connectionStatus: document.getElementById('connectionStatus'),
    geyserStatus: document.getElementById('geyserStatus'),
    sftpStatus: document.getElementById('sftpStatus'),
    backupBtn: document.getElementById('backupBtn'),
    modListSearch: document.getElementById('modListSearch'),
    clearModListSearch: document.getElementById('clearModListSearch'),
    modListPagination: document.getElementById('modListPagination'),
    teleportModal: document.getElementById('teleportModal'),
    teleportPlayerName: document.getElementById('teleportPlayerName'),
    teleportDestination: document.getElementById('teleportDestination'),
    teleportForm: document.getElementById('teleportForm'),
    effectModal: document.getElementById('effectModal'),
    effectPlayerName: document.getElementById('effectPlayerName'),
    effectSelect: document.getElementById('effectSelect'),
    effectForm: document.getElementById('effectForm'),
    sftpBtn: document.getElementById('sftpBtn'),
    sftpBrowserSection: document.getElementById('sftpBrowserSection'),
    sftpIframe: document.getElementById('sftpIframe')
  };

  const loadouts = {
    starter: [
      { item: 'torch', amount: 16 },
      { item: 'cooked_beef', amount: 8 },
      { item: 'stone_pickaxe', amount: 1 }
    ],
    builder: [
      { item: 'stone', amount: 64 },
      { item: 'oak_planks', amount: 64 },
      { item: 'glass', amount: 32 },
      { item: 'ladder', amount: 16 }
    ],
    combat: [
      { item: 'iron_sword', amount: 1 },
      { item: 'leather_chestplate', amount: 1 },
      { item: 'shield', amount: 1 },
      { item: 'arrow', amount: 32 }
    ],
    miner: [
      { item: 'iron_pickaxe', amount: 1, enchantments: [{ name: 'efficiency', level: 2 }] },
      { item: 'torch', amount: 64 },
      { item: 'iron_shovel', amount: 1 },
      { item: 'bucket', amount: 1 }
    ],
    adventurer: [
      { item: 'bow', amount: 1, enchantments: [{ name: 'power', level: 1 }] },
      { item: 'arrow', amount: 64 },
      { item: 'compass', amount: 1 },
      { item: 'map', amount: 1 }
    ],
    alchemist: [
      { item: 'brewing_stand', amount: 1 },
      { item: 'potion', amount: 3, type: 'healing' },
      { item: 'potion', amount: 2, type: 'swiftness' },
      { item: 'nether_wart', amount: 16 }
    ],
    enchanter: [
      { item: 'enchanting_table', amount: 1 },
      { item: 'book', amount: 10 },
      { item: 'lapis_lazuli', amount: 32 },
      { item: 'experience_bottle', amount: 16 }
    ],
    farmer: [
      { item: 'wheat_seeds', amount: 32 },
      { item: 'iron_hoe', amount: 1 },
      { item: 'bone_meal', amount: 16 },
      { item: 'carrot', amount: 8 }
    ],
    nether: [
      { item: 'potion', amount: 2, type: 'fire_resistance' },
      { item: 'obsidian', amount: 10 },
      { item: 'flint_and_steel', amount: 1 },
      { item: 'golden_apple', amount: 1 }
    ],
    end: [
      { item: 'ender_pearl', amount: 16 },
      { item: 'blaze_rod', amount: 8 },
      { item: 'diamond_sword', amount: 1, enchantments: [{ name: 'sharpness', level: 2 }] },
      { item: 'pumpkin', amount: 1 }
    ]
  };

  let state = {
    user: '',
    serverStatus: '',
    memoryPercent: 0,
    cpuPercent: 0,
    keyExpiry: '',
    playerList: '',
    modListHtml: '',
    logUrl: '',
    websiteUrl: '',
    mapUrl: '',
    myLink: '',
    geyserLink: '',
    sftpLink: '',
    holesailHash: '',
    geyserHash: '',
    sftpHash: '',
    hasShownStartNotification: false,
    connectionStatus: '',
    geyserStatus: '',
    sftpStatus: '',
    activeNotifications: new Map(),
    allMods: [],
    currentPlayers: [],
    taglineUpdated: false 

  };

  function showNotification(message, type = 'loading', key = null) {
    if (key && state.activeNotifications.has(key)) {
      const existing = state.activeNotifications.get(key);
      existing.notification.style.opacity = '0';
      setTimeout(() => existing.notification.remove(), 300);
      state.activeNotifications.delete(key);
    }

    const notification = document.createElement('div');
    notification.className = `notification ${type}`;
    notification.innerHTML = `
      ${type === 'loading' ? '<div class="spinner"></div>' : ''}
      <span>${message}</span>
    `;
    elements.notificationContainer.appendChild(notification);

    if (type !== 'loading') {
      setTimeout(() => {
        notification.style.opacity = '0';
        setTimeout(() => {
          notification.remove();
          if (key) state.activeNotifications.delete(key);
        }, 300);
      }, 3000);
    }

    if (key) {
      state.activeNotifications.set(key, { notification, message, type });
    }

    return notification;
  }

  function updateNotification(notification, message, type, key = null) {
    if (key && state.activeNotifications.has(key) && state.activeNotifications.get(key).notification !== notification) {
      const existing = state.activeNotifications.get(key);
      existing.notification.style.opacity = '0';
      setTimeout(() => existing.notification.remove(), 300);
    }

    notification.className = `notification ${type}`;
    notification.innerHTML = `<span>${message}</span>`;

    if (type !== 'loading') {
      setTimeout(() => {
        notification.style.opacity = '0';
        setTimeout(() => {
          notification.remove();
          if (key) state.activeNotifications.delete(key);
        }, 300);
      }, 3000);
    }

    if (key) {
      state.activeNotifications.set(key, { notification, message, type });
    }
  }

  function initializeCharts() {
    if (memoryMeter || cpuMeter) {
      return;
    }

    const memoryCanvas = document.getElementById('memoryMeter');
    if (!memoryCanvas) {
      console.error('Memory Meter canvas not found');
      showNotification('Unable to display memory usage chart: Canvas element missing', 'error');
      return;
    }
    const memoryCtx = memoryCanvas.getContext('2d');
    if (!memoryCtx) {
      console.error('Failed to acquire 2D context for Memory Meter');
      showNotification('Unable to display memory usage chart: Invalid canvas context', 'error');
      return;
    }
    memoryMeter = new Chart(memoryCtx, {
      type: 'doughnut',
      data: {
        datasets: [{
          data: [0, 100],
          backgroundColor: ['#EF4444', '#4B5563'],
          borderWidth: 0,
          circumference: 180,
          rotation: 270
        }]
      },
      options: {
        cutout: '80%',
        responsive: false,
        plugins: { title: { display: false }, tooltip: { enabled: false } }
      }
    });

    const cpuCanvas = document.getElementById('cpuMeter');
    if (!cpuCanvas) {
      console.error('CPU Meter canvas not found');
      showNotification('Unable to display CPU usage chart: Canvas element missing', 'error');
      return;
    }
    const cpuCtx = cpuCanvas.getContext('2d');
    if (!cpuCtx) {
      console.error('Failed to acquire 2D context for CPU Meter');
      showNotification('Unable to display CPU usage chart: Invalid canvas context', 'error');
      return;
    }
    cpuMeter = new Chart(cpuCtx, {
      type: 'doughnut',
      data: {
        datasets: [{
          data: [0, 600],
          backgroundColor: ['#3B82F6', '#4B5563'],
          borderWidth: 0,
          circumference: 180,
          rotation: 270
        }]
      },
      options: {
        cutout: '80%',
        responsive: false,
        plugins: { title: { display: false }, tooltip: { enabled: false } }
      }
    });
  }

  function initializeTerminal() {
    const terminalElement = document.getElementById('dockerLogsTerminal');
  
    // Early return if terminal element is not found
    if (!terminalElement) {
      console.error('Terminal element not found');
      return;
    }
  
    // Reuse existing terminal instance if available
    if (terminal) {
      terminal.clear();
      terminal.reset();
    } else {
      // Lazy-load xterm and addons to reduce initial bundle size
      terminal = new Terminal({
        rows: 50,
        fontSize: 12,
        fontFamily: '"Fira Mono", monospace',
        theme: {
          background: '#121528',
          foreground: '#ffffff',
          cursor: '#ffffff',
          selectionBackground: '#ffffff44', // Improve accessibility
        },
        scrollback: 5000, // Reduced for better memory usage
        rendererType: 'dom', // Use 'dom' for better performance in most cases
        cursorBlink: false, // Disable for better performance
        convertEol: true, // Normalize line endings for consistency
      });
  
      // Initialize FitAddon
      fitAddon = new FitAddon.FitAddon();
      terminal.loadAddon(fitAddon);
  
      // Open terminal and remove border
      terminal.open(terminalElement);
      terminalElement.style.border = 'none';
    }
  
    // Fit terminal to container
    fitAddon.fit();
  
    // Debounced resize handler to prevent excessive reflows
    let resizeTimeout;
    const debouncedResize = () => {
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(() => {
        if (fitAddon && terminal) {
          fitAddon.fit();
        }
      }, 100);
    };
  
    // Clean up previous event listeners to prevent memory leaks
    window.removeEventListener('resize', debouncedResize);
    window.addEventListener('resize', debouncedResize);
  
    // Return terminal instance for external use if needed
    return terminal;
  }
  
  // Optional: Clean up terminal when no longer needed
  function disposeTerminal() {
    if (terminal) {
      terminal.dispose();
      terminal = null;
      fitAddon = null;
    }
  }

  function connectWebSocket() {
    if (ws && ws.readyState === WebSocket.OPEN) {
      return;
    }

    ws = new WebSocket(`wss://${window.location.host}/ws?apiKey=${encodeURIComponent(apiKey)}`);

    ws.onopen = () => {
      showMainContent();
      ws.send(JSON.stringify({
        type: 'subscribe',
        endpoints: [
          'docker',
          'docker-logs',
          'hello',
          'time',
          'list-players',
          'mod-list',
          'log',
          'website',
          'map',
          'my-link-cache',
          'my-geyser-cache',
          'my-sftp-cache',
          'backup',
          'sftp-status',
          'holesail-hashes',
          'internal-sftp'
        ]
      }));
      responseTimeout = setTimeout(() => {
        showNotification('No response from server. Please check your connection or API key.', 'error', 'ws-timeout');
        handleLogout();
      }, 5000);
    };

    ws.onmessage = (event) => {
      try {
        clearTimeout(responseTimeout);
        const message = JSON.parse(event.data);
        // Handle internal-sftp message immediately to save credentials
        if (message.type === 'internal-sftp' && message.data?.hostname && message.data?.port && message.data?.user && message.data?.password) {
          sftpCredentials = {
            hostname: message.data.hostname,
            port: message.data.port,
            user: message.data.user,
            password: message.data.password
          };
          if (!hasAttemptedSftpConnect) {
            hasAttemptedSftpConnect = true;
            connectSftp();
          }
        }
        if (message.requestId && pendingRequests.has(message.requestId)) {
          const { resolve, reject, notification, key } = pendingRequests.get(message.requestId);
          pendingRequests.delete(message.requestId);
          if (message.error) {
            updateNotification(notification, `Error: ${message.error}`, 'error', key);
            if (message.error.includes('Missing token') || message.error.includes('HTTP 403')) {
              showNotification('Invalid or expired API key. Please log in again.', 'error', 'auth-error');
              elements.loginError.classList.remove('hidden');
              elements.loginError.textContent = 'Invalid API key. Please try again.';
              handleLogout();
            }
            reject(new Error(message.error));
          } else {
            updateNotification(notification, message.message || 'Action completed successfully', 'success', key);
            resolve(message.data || message);
          }
        } else {
          updateUI(message);
        }
      } catch (error) {
        console.error('WebSocket message parsing error:', error);
        showNotification('Error processing server data. Please try again.', 'error', 'ws-parse-error');
      }
    };

    ws.onclose = () => {
      showLoginPage();
      clearTimeout(responseTimeout);
      if (terminal) {
        terminal.clear();
      }
      setTimeout(connectWebSocket, 3000);
    };

    ws.onerror = (error) => {
      console.error('WebSocket error:', error);
      showNotification('Failed to connect to server. Please check your network.', 'error', 'ws-error');
    };
  }

  function wsRequest(endpoint, method = 'GET', body = null) {
    return new Promise((resolve, reject) => {
      if (!ws || ws.readyState !== WebSocket.OPEN) {
        showNotification('Not connected to server. Please log in.', 'error', 'ws-disconnected');
        reject(new Error('WebSocket not connected'));
        return;
      }
      const requestId = crypto.randomUUID();
      const action = endpoint.replace('/', '').replace('-', ' ');
      const key = `action-${action}`;
      const notification = showNotification(`Processing ${action}...`, 'loading', key);
      pendingRequests.set(requestId, { resolve, reject, notification, key });
      ws.send(JSON.stringify({ type: 'request', requestId, endpoint, method, body }));
    });
  }

  function updateUI(message) {
    if (message.type === 'docker') {
      updateDockerUI(message);
    } else if (message.type === 'docker-logs') {
      updateDockerLogsUI(message);
    } else if (message.type === 'connection-status') {
      updateConnectionStatusUI(message);
    } else if (message.type === 'geyser-status') {
      updateGeyserStatusUI(message);
    } else if (message.type === 'sftp-status') {
      updateSftpStatusUI(message);
    } else if (message.type === 'my-sftp-cache') {
      updateSftpCacheUI(message);
    } else if (message.type === 'update-mods') {
      updateModsUI(message);
    } else if (message.type === 'backup') {
      console.log('Received backup message:', message);
    } else if (message.type === 'holesail-hashes') {
      updateHolesailHashesUI(message);
    } else {
      updateNonDockerUI(message);
    }
  }

  function updateDockerUI(message) {
    console.log('updateDockerUI called with message:', message);
    if (message.error) {
      console.log('Docker message error:', message.error);
      if (elements.serverStatus) elements.serverStatus.textContent = 'Not Running';
      toggleSections('Not Running');
      return;
    }

    // Reinitialize tagline element to handle dynamic DOM changes
    elements.tagline = document.getElementById('tagline');
    console.log('Tagline element in updateDockerUI:', elements.tagline);

    const memoryPercent = parseFloat(message.data?.memory?.percent) || 0;
    if (state.memoryPercent !== memoryPercent && elements.memoryPercent && memoryMeter) {
      memoryMeter.data.datasets[0].data = [memoryPercent, 100 - memoryPercent];
      memoryMeter.update();
      elements.memoryPercent.textContent = `${memoryPercent.toFixed(1)}%`;
      state.memoryPercent = memoryPercent;
    }

    const cpuPercent = parseFloat(message.data?.cpu) || 0;
    if (state.cpuPercent !== cpuPercent && elements.cpuPercent && cpuMeter) {
      const scaledCpuPercent = Math.min((cpuPercent / 600) * 100, 100);
      cpuMeter.data.datasets[0].data = [scaledCpuPercent, 100 - scaledCpuPercent];
      cpuMeter.update();
      elements.cpuPercent.textContent = `${cpuPercent.toFixed(1)}%`;
      state.cpuPercent = cpuPercent;
    }

    const status = message.data?.status || 'Unknown';
    if (elements.serverStatus) {
      elements.serverStatus.textContent = status;
      state.serverStatus = status;
      toggleSections(status);
    }

    // Update tagline based on RAM only if not already updated
    if (!state.taglineUpdated && elements.tagline) {
      let totalRam = 0;
      if (message.data?.memory?.raw) {
        // Extract total RAM from "2231.52MiB / 8.20GiB" format
        const rawMemory = message.data.memory.raw;
        const totalPart = rawMemory.split('/')[1]?.trim(); // Get "8.20GiB"
        if (totalPart) {
          const match = totalPart.match(/^(\d+\.\d+|\d+)(GiB|MiB)$/);
          if (match) {
            const value = parseFloat(match[1]);
            const unit = match[2];
            totalRam = unit === 'GiB' ? value * 1024 : value; // Convert GiB to MiB
          }
        }
      }
      console.log('Total RAM (MiB):', totalRam);
      console.log('Tagline element before update:', elements.tagline.textContent);
      // Use tolerance to account for floating-point discrepancies
      const tolerance = 50; // Allow 50 MiB leeway
      if (totalRam >= 11000 - tolerance) {
        elements.tagline.textContent = 'Manage Your Super Premium Minecraft Server';
        console.log('Set tagline to: Manage Your Super Premium Minecraft Server');
      } else if (totalRam >= 8000 - tolerance) {
        elements.tagline.textContent = 'Manage Your Premium Minecraft Server';
        console.log('Set tagline to: Manage Your Premium Minecraft Server');
      } else {
        elements.tagline.textContent = 'Manage Your Minecraft Server';
        console.log('Set tagline to: Manage Your Minecraft Server');
      }
      console.log('Tagline element after update:', elements.tagline.textContent);
      state.taglineUpdated = true; // Mark tagline as updated
    } else if (!elements.tagline) {
      console.error('Tagline element not found in updateDockerUI');
      showNotification('Failed to update tagline: Element not found', 'error', 'tagline-error');
    } else {
      console.log('Tagline already updated, skipping calculations');
    }
  }


    // Reinitialize tagline element to handle dynamic DOM changes
    elements.tagline = document.getElementById('tagline');

  function toggleSections(status) {
    const sections = document.querySelectorAll('.section-bg');
    const serverStatusSection = document.querySelector('.section-bg[data-section="server-status"]');
    const editPropertiesBtn = elements.editPropertiesBtn;
    const updateModsBtn = elements.updateModsBtn;
    const sftpBtn = elements.sftpBtn;
    const startBtn = document.getElementById('startBtn');
    const stopBtn = elements.stopBtn;
    const restartBtn = elements.restartBtn;
    const sftpBrowserSection = elements.sftpBrowserSection;
    const refreshBtn = elements.refresh || document.getElementById('refresh');
    const mobileRefreshBtn = elements.mobileRefresh || document.getElementById('mobileRefresh');
    const backupBtn = elements.backupBtn;
    const mobileBackupBtn = elements.mobileBackupBtn;
    const logoutBtn = elements.logoutBtn || document.getElementById('logoutBtn');
    const mobileLogoutBtn = elements.mobileLogoutBtn || document.getElementById('mobileLogoutBtn');

    if (startBtn) {
      if (status.toLowerCase() === 'running') {
        startBtn.disabled = true;
        startBtn.classList.add('disabled-btn');
      } else {
        startBtn.disabled = false;
        startBtn.classList.remove('disabled-btn');
      }
    }

    if (status.toLowerCase() !== 'running') {
      sections.forEach(section => {
        if (section !== serverStatusSection) {
          section.classList.add('hidden');
        }
      });
      if (editPropertiesBtn) {
        editPropertiesBtn.classList.add('hidden');
        editPropertiesBtn.style.display = 'none';
      }
      if (updateModsBtn) {
        updateModsBtn.classList.add('hidden');
        updateModsBtn.style.display = 'none';
      }
      if (sftpBtn) {
        sftpBtn.classList.add('hidden');
      }
      if (stopBtn) {
        stopBtn.disabled = true;
        stopBtn.classList.add('disabled-btn');
      }
      if (restartBtn) {
        restartBtn.disabled = true;
        restartBtn.classList.add('disabled-btn');
      }
      if (sftpBrowserSection) {
        sftpBrowserSection.style.display = 'none';
      }
      if (refreshBtn) {
        refreshBtn.classList.add('hidden');
        refreshBtn.style.display = 'none';
      }
      if (backupBtn) {
        backupBtn.classList.add('hidden');
        backupBtn.style.display = 'none';
      }
      if (logoutBtn) {
        logoutBtn.classList.add('hidden');
        logoutBtn.style.display = 'none';
      }
      if (mobileRefreshBtn && mobileRefreshBtn.parentElement) {
        mobileRefreshBtn.parentElement.classList.add('hidden');
      }
      if (mobileBackupBtn && mobileBackupBtn.parentElement) {
        mobileBackupBtn.parentElement.classList.add('hidden');
      }
      if (mobileLogoutBtn && mobileLogoutBtn.parentElement) {
        mobileLogoutBtn.parentElement.classList.add('hidden');
      }
      if (!state.hasShownStartNotification) {
        showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped');
        state.hasShownStartNotification = true;
      }
    } else {
      sections.forEach(section => {
        section.classList.remove('hidden');
      });
      if (editPropertiesBtn) {
        editPropertiesBtn.classList.remove('hidden');
        editPropertiesBtn.style.display = '';
      }
      if (updateModsBtn) {
        updateModsBtn.classList.remove('hidden');
        updateModsBtn.style.display = '';
      }
      if (sftpBtn) {
        sftpBtn.classList.remove('hidden');
      }
      if (stopBtn) {
        stopBtn.disabled = false;
        stopBtn.classList.remove('disabled-btn');
      }
      if (restartBtn) {
        restartBtn.disabled = false;
        restartBtn.classList.remove('disabled-btn');
      }
      if (sftpBrowserSection) {
        sftpBrowserSection.style.display = 'block';
      }
      if (refreshBtn) {
        refreshBtn.classList.remove('hidden');
        refreshBtn.style.display = '';
      }
      if (backupBtn) {
        backupBtn.classList.remove('hidden');
        refreshBtn.style.display = '';
      }
      if (logoutBtn) {
        logoutBtn.classList.remove('hidden');
        logoutBtn.style.display = '';
      }
      if (mobileRefreshBtn && mobileRefreshBtn.parentElement) {
        mobileRefreshBtn.parentElement.classList.remove('hidden');
      }
      if (mobileBackupBtn && mobileBackupBtn.parentElement) {
        mobileBackupBtn.parentElement.classList.remove('hidden');
      }
      if (mobileLogoutBtn && mobileLogoutBtn.parentElement) {
        mobileLogoutBtn.parentElement.classList.remove('hidden');
      }
      state.hasShownStartNotification = false;
    }
  }

  function updateDockerLogsUI(message) {
    if (message.error) {
      return;
    }
    if (message.data?.log && terminal) {
      const logLines = message.data.log.split('\n');
      const cleanedLog = logLines
        .map(line =>
          line
            .replace(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s*/, '')
            .replace(/\u001b\[32m0\|MineCraft Server\s*\|\s*\u001b\[39m/, '')
        )
        .join('\n');
      terminal.write(cleanedLog);
      const lines = terminal.buffer.active.length;
      if (lines > 8) {
        terminal.scrollToLine(lines - 8);
      }
      if (fitAddon) {
        fitAddon.fit();
      }
    }
  }

  function updateConnectionStatusUI(message) {
    if (message.data?.isOnline !== undefined && elements.connectionStatus) {
      const statusIcon = message.data.isOnline ? '✅' : '❌';
      if (state.connectionStatus !== statusIcon) {
        elements.connectionStatus.textContent = statusIcon;
        state.connectionStatus = statusIcon;
      }
    }
  }

  function updateGeyserStatusUI(message) {
    if (message.data?.isOnline !== undefined && elements.geyserStatus) {
      const statusIcon = message.data.isOnline ? '✅' : '❌';
      if (state.geyserStatus !== statusIcon) {
        elements.geyserStatus.textContent = statusIcon;
        state.geyserStatus = statusIcon;
      }
    }
  }

  function updateSftpStatusUI(message) {
    if (message.data?.isOnline !== undefined && elements.sftpStatus) {
      const statusIcon = message.data.isOnline ? '✅' : '❌';
      isSftpOnline = message.data.isOnline;
      if (state.sftpStatus !== statusIcon) {
        elements.sftpStatus.textContent = statusIcon;
        state.sftpStatus = statusIcon;
      }
    }
  }

  function updateSftpCacheUI(message) {
    if (message.data?.hostname && message.data?.port && message.data?.user && message.data?.password) {
      const sftpLinkText = `${message.data.hostname}:${message.data.port}`;
      if (state.sftpLink !== sftpLinkText && elements.sftpLink) {
        elements.sftpLink.textContent = sftpLinkText;
        state.sftpLink = sftpLinkText;
      }
    }
  }

  function updateHolesailHashesUI(message) {
    if (message.error) {
      showNotification(`Failed to load Holesail hashes: ${message.error}`, 'error', 'holesail-hashes-error');
      return;
    }

    if (message.data?.myHash && elements.holesailHash) {
      const hashText = message.data.myHash;
      if (state.holesailHash !== hashText) {
        elements.holesailHash.textContent = hashText;
        state.holesailHash = hashText;
      }
    }

    if (message.data?.geyserHash && elements.geyserHash) {
      const hashText = message.data.geyserHash;
      if (state.geyserHash !== hashText) {
        elements.geyserHash.textContent = hashText;
        state.geyserHash = hashText;
      }
    }

    if (message.data?.sftpHash && elements.sftpHash) {
      const hashText = message.data.sftpHash;
      if (state.sftpHash !== hashText) {
        elements.sftpHash.textContent = hashText;
        state.sftpHash = hashText;
      }
    }

    if (message.data?.errors?.length > 0) {
      message.data.errors.forEach(error => {
        showNotification(error, 'error', `holesail-hashes-error-${error}`);
      });
    }
  }

  function updateModsUI(message) {
    if (message.error) {
      elements.updateModsOutput.textContent = `Error: ${message.error}`;
    } else if (message.output) {
      elements.updateModsOutput.textContent = message.output;
    }
    elements.updateModsModal.classList.remove('hidden');
  }

  function updateNonDockerUI(message) {
    if (message.error) {
      if (message.error.includes('Missing token') || message.error.includes('HTTP 403')) {
        showNotification('Invalid or expired API key. Please log in again.', 'error', 'auth-error');
        elements.loginError.classList.remove('hidden');
        elements.loginError.textContent = 'Invalid API key. Please try again.';
        handleLogout();
      }
      return;
    }

    if (message.type === 'hello' && message.data?.message) {
      const user = message.data.message.split(', ')[1]?.replace('!', '').trim() || 'Unknown';
      if (state.user !== user && elements.user) {
        elements.user.textContent = user;
        state.user = user;
        if (ws && ws.readyState === WebSocket.OPEN) {
          ws.send(JSON.stringify({ type: 'updateUser', user }));
        }
      }
    }

    if (message.type === 'list-players' && message.data?.players) {
      const players = message.data.players || [];
      state.currentPlayers = players;
      const isSinglePlayer = players.length <= 1;
    
      state.actionButtonStates = state.actionButtonStates || {};
    
      const playerListHtml = players.length > 0
        ? players.map(player => {
            const isActionButtonsVisible = state.actionButtonStates[player] || false;
            return `
    <div class="flex items-center space-x-4 mb-2">
      <span class="w-32">${player}</span>
      <div class="flex flex-col gap-2">
        <button class="toggle-actions bg-gray-600 hover:bg-gray-700 px-2 py-1 rounded text-sm" data-player="${player}" ${isActionButtonsVisible ? 'hidden' : ''}>Actions</button>
        <div class="action-buttons flex-wrap gap-2 ${isActionButtonsVisible ? '' : 'hidden'}" data-player="${player}">
          <button class="tell-player bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded text-sm" data-player="${player}">Tell</button>
          <button class="give-player bg-green-600 hover:bg-green-700 px-2 py-1 rounded text-sm" data-player="${player}">Give</button>
          <button class="teleport-player bg-cyan-600 hover:bg-cyan-700 px-2 py-1 rounded text-sm ${isSinglePlayer ? 'opacity-50 cursor-not-allowed' : ''}" data-player="${player}" ${isSinglePlayer ? 'disabled' : ''}>Teleport</button>
          <button class="effect-player bg-teal-600 hover:bg-teal-700 px-2 py-1 rounded text-sm" data-player="${player}">Effect</button>
          <button class="op-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Op</button>
          <button class="deop-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Deop</button>
          <button class="kick-player bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm" data-player="${player}">Kick</button>
          <button class="ban-player bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm" data-player="${player}">Ban</button>
          <button class="close-actions bg-gray-600 hover:bg-gray-700 px-2 py-1 rounded text-sm" data-player="${player}">Close</button>
        </div>
      </div>
    </div>
    `;
          }).join('')
        : 'None';
    
      if (state.playerList !== playerListHtml && elements.playerList) {
        elements.playerList.innerHTML = playerListHtml;
        state.playerList = playerListHtml;
    
        const toggleButtons = document.querySelectorAll('.toggle-actions');
        const closeButtons = document.querySelectorAll('.close-actions');
        toggleButtons.forEach(button => {
          button.replaceWith(button.cloneNode(true));
        });
        closeButtons.forEach(button => {
          button.replaceWith(button.cloneNode(true));
        });
    
        document.querySelectorAll('.toggle-actions').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            const actionDiv = document.querySelector(`.action-buttons[data-player="${player}"]`);
            if (actionDiv) {
              actionDiv.classList.remove('hidden');
              button.classList.add('hidden');
              state.actionButtonStates[player] = true;
            }
          });
        });
    
        document.querySelectorAll('.close-actions').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            const actionDiv = document.querySelector(`.action-buttons[data-player="${player}"]`);
            const toggleButton = document.querySelector(`.toggle-actions[data-player="${player}"]`);
            if (actionDiv && toggleButton) {
              actionDiv.classList.add('hidden');
              toggleButton.classList.remove('hidden');
              state.actionButtonStates[player] = false;
            }
          });
        });

        document.querySelectorAll('.tell-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            elements.tellPlayerName.textContent = player;
            elements.tellMessage.value = '';
            elements.tellModal.classList.remove('hidden');
          });
        });

        document.querySelectorAll('.give-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            elements.givePlayerName.textContent = player;
            elements.loadoutSelect.value = 'custom';
            elements.customGiveFields.classList.remove('hidden');
            resetItemFields();
            elements.giveModal.classList.remove('hidden');
          });
        });

        document.querySelectorAll('.teleport-player').forEach(button => {
          if (!button.disabled) {
            button.addEventListener('click', () => {
              const player = button.getAttribute('data-player').trim();
              if (!player) {
                showNotification('Invalid player name.', 'error');
                return;
              }
              elements.teleportPlayerName.textContent = player;
              elements.teleportDestination.innerHTML = state.currentPlayers
                .filter(p => p !== player)
                .map(p => `<option value="${p}">${p}</option>`)
                .join('');
              elements.teleportModal.classList.remove('hidden');
            });
          }
        });

        document.querySelectorAll('.effect-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            elements.effectPlayerName.textContent = player;
            elements.effectSelect.value = 'speed:30:1';
            elements.effectModal.classList.remove('hidden');
          });
        });

        document.querySelectorAll('.kick-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            try {
              const requestId = crypto.randomUUID();
              const key = `action-kick-player-${player}`;
              const notification = showNotification(`Kicking player ${player}...`, 'loading', key);
              pendingRequests.set(requestId, {
                resolve: () => {
                  updateNotification(notification, `Player ${player} kicked successfully`, 'success', key);
                  wsRequest('/list-players').then(response => {
                    updateNonDockerUI({ type: 'list-players', data: response });
                  });
                },
                reject: (error) => {
                  updateNotification(notification, `Failed to kick player ${player}: ${error.message}`, 'error', key);
                },
                notification,
                key
              });
              ws.send(JSON.stringify({ type: 'kick-player', requestId, player }));
            } catch (error) {
              console.error(`Kick player ${player} error:`, error);
              showNotification(`Failed to kick player ${player}: ${error.message}`, 'error');
            }
          });
        });

        document.querySelectorAll('.ban-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            try {
              const requestId = crypto.randomUUID();
              const key = `action-ban-player-${player}`;
              const notification = showNotification(`Banning player ${player}...`, 'loading', key);
              pendingRequests.set(requestId, {
                resolve: () => {
                  updateNotification(notification, `Player ${player} banned successfully`, 'success', key);
                  wsRequest('/list-players').then(response => {
                    updateNonDockerUI({ type: 'list-players', data: response });
                  });
                },
                reject: (error) => {
                  updateNotification(notification, `Failed to ban player ${player}: ${error.message}`, 'error', key);
                },
                notification,
                key
              });
              ws.send(JSON.stringify({ type: 'ban-player', requestId, player }));
            } catch (error) {
              console.error(`Ban player ${player} error:`, error);
              showNotification(`Failed to ban player ${player}: ${error.message}`, 'error');
            }
          });
        });

        document.querySelectorAll('.op-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            try {
              const requestId = crypto.randomUUID();
              const key = `action-op-player-${player}`;
              const notification = showNotification(`Granting operator status to ${player}...`, 'loading', key);
              pendingRequests.set(requestId, {
                resolve: () => {
                  updateNotification(notification, `Operator status granted to ${player}`, 'success', key);
                  wsRequest('/list-players').then(response => {
                    updateNonDockerUI({ type: 'list-players', data: response });
                  });
                },
                reject: (error) => {
                  updateNotification(notification, `Failed to grant operator status to ${player}: ${error.message}`, 'error', key);
                },
                notification,
                key
              });
              ws.send(JSON.stringify({ type: 'op-player', requestId, player }));
            } catch (error) {
              console.error(`Op player ${player} error:`, error);
              showNotification(`Failed to grant operator status to ${player}: ${error.message}`, 'error');
            }
          });
        });

        document.querySelectorAll('.deop-player').forEach(button => {
          button.addEventListener('click', () => {
            const player = button.getAttribute('data-player').trim();
            if (!player) {
              showNotification('Invalid player name.', 'error');
              return;
            }
            try {
              const requestId = crypto.randomUUID();
              const key = `action-deop-player-${player}`;
              const notification = showNotification(`Removing operator status from ${player}...`, 'loading', key);
              pendingRequests.set(requestId, {
                resolve: () => {
                  updateNotification(notification, `Operator status removed from ${player}`, 'success', key);
                  wsRequest('/list-players').then(response => {
                    updateNonDockerUI({ type: 'list-players', data: response });
                  });
                },
                reject: (error) => {
                  updateNotification(notification, `Failed to remove operator status from ${player}: ${error.message}`, 'error', key);
                },
                notification,
                key
              });
              ws.send(JSON.stringify({ type: 'deop-player', requestId, player }));
            } catch (error) {
              console.error(`Deop player ${player} error:`, error);
              showNotification(`Failed to remove operator status from ${player}: ${error.message}`, 'error');
            }
          });
        });
      }
    }

    if (message.type === 'mod-list' && message.data?.mods) {
      state.allMods = message.data.mods || [];
      renderModList();
    }

    if (message.type === 'log' && message.data?.message) {
      if (state.logUrl !== message.data.message && elements.logUrl) {
        elements.logUrl.href = message.data.message;
        elements.logUrl.textContent = "Visit Log";
        state.logUrl = message.data.message;
      }
    }

    if (message.type === 'website' && message.data?.message) {
      if (state.websiteUrl !== message.data.message && elements.websiteUrl) {
        elements.websiteUrl.href = message.data.message;
        elements.websiteUrl.textContent = "Visit Website";
        state.websiteUrl = message.data.message;
      }
    }

    if (message.type === 'map' && message.data?.message) {
      if (state.mapUrl !== message.data.message && elements.mapUrl) {
        elements.mapUrl.href = message.data.message;
        elements.mapUrl.textContent = "Visit Map";
        state.mapUrl = message.data.message;
      }
    }

    if (message.type === 'my-link-cache' && message.data?.hostname && message.data?.port) {
      const myLinkText = `${message.data.hostname}:${message.data.port}`;
      if (state.myLink !== myLinkText && elements.myLink) {
        elements.myLink.textContent = myLinkText;
        state.myLink = myLinkText;
      }
    }

    if (message.type === 'my-geyser-cache' && message.data?.hostname && message.data?.port) {
      const geyserLinkText = `${message.data.hostname}:${message.data.port}`;
      if (state.geyserLink !== geyserLinkText && elements.geyserLink) {
        elements.geyserLink.textContent = geyserLinkText;
        state.geyserLink = geyserLinkText;
      }
    }

    if (message.type === 'my-link' && message.data?.hostname && message.data?.port) {
      const myLinkText = `${message.data.hostname}:${message.data.port}`;
      if (state.myLink !== myLinkText && elements.myLink) {
        elements.myLink.textContent = myLinkText;
        state.myLink = myLinkText;
      }
    }

    if (message.type === 'my-geyser-link' && message.data?.hostname && message.data?.port) {
      const geyserLinkText = `${message.data.hostname}:${message.data.port}`;
      if (state.geyserLink !== geyserLinkText && elements.geyserLink) {
        elements.geyserLink.textContent = geyserLinkText;
        state.geyserLink = geyserLinkText;
      }
    }

    if (message.type === 'my-sftp' && message.data?.hostname && message.data?.port && message.data?.user) {
      const sftpLinkText = `${message.data.hostname}:${message.data.port} (User: ${message.data.user})`;
      if (state.sftpLink !== sftpLinkText && elements.sftpLink) {
        elements.sftpLink.textContent = sftpLinkText;
        state.sftpLink = sftpLinkText;
      }
    }
  }

  function showLoginPage() {
    if (!elements.loginPage || !elements.mainContent) {
      console.error('Required elements not found:', {
        loginPage: elements.loginPage,
        mainContent: elements.mainContent
      });
      showNotification('Page error: Essential elements missing. Please refresh the page.', 'error', 'page-error');
      return;
    }
    elements.loginPage.classList.remove('hidden');
    elements.mainContent.classList.add('hidden');
    elements.apiKeyInput = document.getElementById('apiKey');
    if (ws) {
      ws.close();
      ws = null;
    }
    if (memoryMeter) {
      memoryMeter.destroy();
      memoryMeter = null;
    }
    if (cpuMeter) {
      cpuMeter.destroy();
      cpuMeter = null;
    }
    if (terminal) {
      terminal.clear();
    }
  }

  function showMainContent() {
    const apiKey = localStorage.getItem('apiKey');
    if (!apiKey) {
        console.error('API key not found in localStorage');
        return;
    }

    if (!elements.loginPage || !elements.mainContent) {
        console.error('Required elements not found:', {
            loginPage: elements.loginPage,
            mainContent: elements.mainContent
        });
        showNotification('Page error: Essential elements missing. Please refresh the page.', 'error', 'page-error');
        return;
    }

    elements.loginPage.classList.add('hidden');
    elements.mainContent.classList.remove('hidden');

    const logoutBtn = document.getElementById('logoutBtn');
    const mobileLogoutBtn = document.getElementById('mobileLogoutBtn');

    if (logoutBtn) {
        console.log('Desktop logout button found');
    } else {
        console.error('Desktop logout button (#logoutBtn) not found');
    }

    if (mobileLogoutBtn) {
        console.log('Mobile logout button found');
    } else {
        console.error('Mobile logout button (#mobileLogoutBtn) not found');
    }

    document.removeEventListener('click', handleLogoutClick);

    function handleLogoutClick(event) {
        if (event.target.id === 'logoutBtn' || event.target.id === 'mobileLogoutBtn') {
            console.log(`Logout button clicked: ${event.target.id}`);
            handleLogout();
        }
    }

    document.addEventListener('click', handleLogoutClick);

    initializeCharts();
    initializeTerminal();
}

  function handleApiKeyChange(e) {
    apiKey = e.target.value.trim();
    if (apiKey) {
      localStorage.setItem('apiKey', apiKey);
      elements.loginError.classList.add('hidden');
      connectWebSocket();
    }
  }

  function handleLogout() {
    apiKey = '';
    localStorage.removeItem('apiKey');
    showLoginPage();
  }

  async function handleRefresh() {
    if (ws && ws.readyState === WebSocket.OPEN) {
      const key = `action-refresh`;
      const notification = showNotification('Refreshing server data...', 'loading', key);
      ws.send(JSON.stringify({ type: 'refresh' }));
      initializeTerminal();
      setTimeout(() => updateNotification(notification, 'Server data refreshed successfully', 'success', key), 1000);
    } else {
      showNotification('Not connected to server. Please log in.', 'error', 'ws-disconnected');
    }
  }

  function updatePagination() {
    const totalPages = Math.max(1, Math.ceil(totalResults / resultsPerPage));
    elements.pagination.innerHTML = '';

    const createPageButton = (page, text, disabled = false) => {
      const button = document.createElement('button');
      button.textContent = text;
      button.className = `nav-btn ${disabled || page === currentPage
        ? 'disabled'
        : 'active'
        }`;
      if (!disabled && page !== currentPage) {
        button.addEventListener('click', () => {
          currentPage = page;
          searchMods();
        });
      }
      elements.pagination.appendChild(button);
    };

    if (totalResults > 0) {
      createPageButton(currentPage - 1, 'Previous', currentPage === 1);
      const maxButtons = 5;
      const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2));
      const endPage = Math.min(totalPages, startPage + maxButtons - 1);
      for (let i = startPage; i <= endPage; i++) {
        createPageButton(i, i.toString());
      }
      createPageButton(currentPage + 1, 'Next', currentPage === totalPages);
    }
  }

  function updateModListPagination() {
    const filteredMods = state.allMods.filter(mod =>
      mod.name.toLowerCase().includes(modListSearchQuery.toLowerCase())
    );
    const totalModPages = Math.max(1, Math.ceil(filteredMods.length / resultsPerPage));
    elements.modListPagination.innerHTML = '';

    const createPageButton = (page, text, disabled = false) => {
      const button = document.createElement('button');
      button.textContent = text;
      button.className = `nav-btn ${disabled || page === modListCurrentPage
        ? 'disabled'
        : 'active'
        }`;
      if (!disabled && page !== modListCurrentPage) {
        button.addEventListener('click', () => {
          modListCurrentPage = page;
          renderModList();
        });
      }
      elements.modListPagination.appendChild(button);
    };

    if (filteredMods.length > 0) {
      createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1);
      const maxButtons = 5;
      const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2));
      const endPage = Math.min(totalModPages, startPage + maxButtons - 1);
      for (let i = startPage; i <= endPage; i++) {
        createPageButton(i, i.toString());
      }
      createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages);
    }
  }

  function closeSearch() {
    elements.modSearch.value = '';
    elements.modResults.innerHTML = '';
    elements.pagination.innerHTML = '';
    elements.closeSearchBtn.classList.add('hidden');
    currentPage = 1;
    totalResults = 0;
  }

  function clearModListSearch() {
    elements.modListSearch.value = '';
    modListSearchQuery = '';
    modListCurrentPage = 1;
    elements.clearModListSearch.classList.add('hidden');
    renderModList();
  }

  function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  async function searchMods(page = currentPage) {
    currentPage = page;
    const mod = elements.modSearch.value.trim();
    if (mod) {
      try {
        const offset = (currentPage - 1) * resultsPerPage;
        const key = `action-search-mods-${mod}`;
        const notification = showNotification(`Searching for mods matching "${mod}"...`, 'loading', key);
        const response = await wsRequest('/search', 'POST', { mod, offset });
        if (elements.modResults) {
          totalResults = response.totalHits || response.results?.length || 0;
          elements.modResults.innerHTML = response.results?.length > 0 ? response.results.map(result => `
            <div class="bg-gray-700 p-4 rounded">
              <p><strong>${result.title}</strong></p>
              <p>${result.description}</p>
              <p>Downloads: ${result.downloads}</p>
              <button class="install-mod bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded mt-2" data-mod-id="${result.installID}">Install</button>
            </div>
          `).join('') : '<p class="text-gray-400">No results found.</p>';
          updatePagination();
          elements.closeSearchBtn.classList.remove('hidden');
          updateNotification(notification, `Found ${totalResults} mod${totalResults === 1 ? '' : 's'} for "${mod}"`, 'success', key);
          document.querySelectorAll('.install-mod').forEach(button => {
            button.addEventListener('click', async () => {
              const modId = button.getAttribute('data-mod-id');
              const installKey = `action-install-mod-${modId}`;
              try {
                await wsRequest('/install', 'POST', { mod: modId });
                const modResponse = await wsRequest('/mod-list');
                updateNonDockerUI({ type: 'mod-list', data: modResponse });
                showNotification(`Mod ${modId} installed successfully`, 'success', installKey);
              } catch (error) {
                console.error('Install mod error:', error);
                showNotification(`Failed to install mod ${modId}: ${error.message}`, 'error', installKey);
              }
            });
          });
        }
      } catch (error) {
        console.error('Search mods error:', error);
        showNotification(`Failed to search mods: ${error.message}`, 'error', key);
      }
    } else {
      showNotification('Please enter a mod name to search.', 'error', 'search-mods-error');
    }
  }

  function renderModList() {
    const filteredMods = state.allMods.filter(mod =>
      mod.name.toLowerCase().includes(modListSearchQuery.toLowerCase())
    );
    const startIndex = (modListCurrentPage - 1) * resultsPerPage;
    const endIndex = startIndex + resultsPerPage;
    const paginatedMods = filteredMods.slice(startIndex, endIndex);

    const modListHtml = paginatedMods.length > 0
      ? paginatedMods.map(mod => `
        <div class="bg-gray-700 p-4 rounded">
          <p><strong>${mod.name}</strong> (${mod.version})</p>
          <p>ID: ${mod.id}</p>
          <button class="uninstall-mod bg-red-600 hover:bg-red-700 px-2 py-1 rounded mt-2" data-mod-id="${mod.id}">Uninstall</button>
        </div>
      `).join('')
      : '<p class="text-gray-400">No mods found.</p>';

    if (state.modListHtml !== modListHtml && elements.modList) {
      elements.modList.innerHTML = modListHtml;
      state.modListHtml = modListHtml;
      document.querySelectorAll('.uninstall-mod').forEach(button => {
        button.addEventListener('click', async () => {
          const modId = button.getAttribute('data-mod-id');
          const key = `action-uninstall-mod-${modId}`;
          try {
            await wsRequest('/uninstall', 'POST', { mod: modId });
            const response = await wsRequest('/mod-list');
            updateNonDockerUI({ type: 'mod-list', data: response });
            showNotification(`Mod ${modId} uninstalled successfully`, 'success', key);
          } catch (error) {
            console.error('Uninstall mod error:', error);
            showNotification(`Failed to uninstall mod ${modId}: ${error.message}`, 'error', key);
          }
        });
      });
    }

    updateModListPagination();
  }

  async function sendConsoleCommand() {
    const command = elements.consoleInput.value.trim();
    if (command) {
      try {
        const key = `action-console-command`;
        const notification = showNotification(`Executing command "${command}"...`, 'loading', key);
        const response = await wsRequest('/console', 'POST', { command });
        if (elements.consoleOutput) {
          elements.consoleOutput.textContent += `> ${command}\n${response.message}\n`;
          elements.consoleInput.value = '';
          updateNotification(notification, `Command "${command}" executed successfully`, 'success', key);
        }
      } catch (error) {
        if (elements.consoleOutput) {
          elements.consoleOutput.textContent += `> ${command}\nError: ${error.message}\n`;
        }
        console.error('Console command error:', error);
        showNotification(`Failed to execute command "${command}": ${error.message}`, 'error', 'console-error');
      }
    }
  }

  async function sendTellMessage() {
    const player = elements.tellPlayerName.textContent.trim();
    const message = elements.tellMessage.value.trim();
    if (!player || !message) {
      showNotification('Player name and message are required.', 'error', 'tell-error');
      return;
    }
    try {
      const requestId = crypto.randomUUID();
      const key = `action-tell-player-${player}`;
      const notification = showNotification(`Sending message to ${player}...`, 'loading', key);
      pendingRequests.set(requestId, {
        resolve: () => {
          updateNotification(notification, `Message sent to ${player} successfully`, 'success', key);
          elements.tellModal.classList.add('hidden');
        },
        reject: (error) => {
          updateNotification(notification, `Failed to send message to ${player}: ${error.message}`, 'error', key);
        },
        notification,
        key
      });
      ws.send(JSON.stringify({ type: 'tell-player', requestId, player, message }));
    } catch (error) {
      console.error(`Send message to ${player} error:`, error);
      showNotification(`Failed to send message to ${player}: ${error.message}`, 'error', 'tell-error');
    }
  }

  async function sendTeleportCommand() {
    const player = elements.teleportPlayerName.textContent.trim();
    const destination = elements.teleportDestination.value.trim();
    if (!player || !destination) {
      showNotification('Source and destination players are required.', 'error', 'teleport-error');
      return;
    }
    try {
      const command = `tp ${player} ${destination}`;
      const key = `action-teleport-player-${player}`;
      const notification = showNotification(`Teleporting ${player} to ${destination}...`, 'loading', key);
      const response = await wsRequest('/console', 'POST', { command });
      updateNotification(notification, `Teleported ${player} to ${destination} successfully`, 'success', key);
      elements.teleportModal.classList.add('hidden');
    } catch (error) {
      console.error(`Teleport ${player} error:`, error);
      showNotification(`Failed to teleport ${player}: ${error.message}`, 'error', 'teleport-error');
    }
  }

  async function sendEffectCommand() {
    const player = elements.effectPlayerName.textContent.trim();
    const effectData = elements.effectSelect.value.split(':');
    const effect = effectData[0];
    const duration = parseInt(effectData[1], 10);
    const amplifier = parseInt(effectData[2], 10);
    if (!player || !effect) {
      showNotification('Player name and effect are required.', 'error', 'effect-error');
      return;
    }
    try {
      const command = `effect give ${player} minecraft:${effect} ${duration} ${amplifier}`;
      const key = `action-effect-player-${player}`;
      const notification = showNotification(`Applying ${effect} to ${player}...`, 'loading', key);
      const response = await wsRequest('/console', 'POST', { command });
      updateNotification(notification, `Applied ${effect} to ${player} successfully`, 'success', key);
      elements.effectModal.classList.add('hidden');
    } catch (error) {
      console.error(`Apply effect to ${player} error:`, error);
      showNotification(`Failed to apply effect to ${player}: ${error.message}`, 'error', 'effect-error');
    }
  }

  function addItemField() {
    const itemList = elements.itemList;
    const itemEntry = document.createElement('div');
    itemEntry.className = 'item-entry flex space-x-2 items-center';
    itemEntry.innerHTML = `
      <input type="text" placeholder="e.g., torch" class="item-name bg-gray-700 px-4 py-2 rounded text-white flex-grow">
      <input type="number" min="1" value="1" class="item-amount bg-gray-700 px-4 py-2 rounded text-white w-20">
      <button type="button" class="remove-item bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm">Remove</button>
    `;
    itemList.appendChild(itemEntry);

    itemEntry.querySelector('.remove-item').addEventListener('click', () => {
      itemEntry.remove();
    });
  }

  function resetItemFields() {
    elements.itemList.innerHTML = '';
    addItemField();
  }

  async function sendGiveCommand() {
    const player = elements.givePlayerName.textContent.trim();
    const loadout = elements.loadoutSelect.value;
    let items = [];

    if (loadout === 'custom') {
      const itemEntries = document.querySelectorAll('.item-entry');
      items = Array.from(itemEntries).map(entry => {
        const item = entry.querySelector('.item-name').value.trim();
        const amount = parseInt(entry.querySelector('.item-amount').value, 10);
        return { item, amount };
      }).filter(itemData => itemData.item && itemData.amount > 0);

      if (items.length === 0) {
        showNotification('At least one valid item and quantity are required.', 'error', 'give-error');
        return;
      }
    } else {
      items = loadouts[loadout] || [];
    }

    try {
      const key = `action-give-player-${player}`;
      const notification = showNotification(`Giving items to ${player}...`, 'loading', key);
      for (const itemData of items) {
        const { item, amount, enchantments, type } = itemData;
        const requestId = crypto.randomUUID();
        pendingRequests.set(requestId, {
          resolve: () => {
            updateNotification(notification, `Gave ${amount} ${item}${type ? ` (${type})` : ''} to ${player}`, 'success', key);
          },
          reject: (error) => {
            updateNotification(notification, `Failed to give ${item} to ${player}: ${error.message}`, 'error', key);
          },
          notification,
          key
        });
        ws.send(JSON.stringify({
          type: 'give-player',
          requestId,
          player,
          item,
          amount,
          enchantments: enchantments || undefined,
          potionType: type || undefined
        }));
      }
      elements.giveModal.classList.add('hidden');
    } catch (error) {
      console.error(`Give items to ${player} error:`, error);
      showNotification(`Failed to give items to ${player}: ${error.message}`, 'error', 'give-error');
    }
  }

  let displayProperties = {};

  function parseServerProperties(content) {
    const properties = {};
    const lines = content.split('\n');
    lines.forEach(line => {
      if (line.trim() && !line.trim().startsWith('#')) {
        const [key, value] = line.split('=', 2).map(part => part.trim());
        if (key && value !== undefined) {
          properties[key] = value;
        }
      }
    });
    return properties;
  }

  function renderPropertiesFields(properties, filter = '') {
    const fieldsContainer = elements.propertiesFields;

    let searchContainer = fieldsContainer.querySelector('#searchContainer');
    if (!searchContainer) {
      searchContainer = document.createElement('div');
      searchContainer.id = 'searchContainer';
      searchContainer.className = 'mb-4';
      searchContainer.style.display = 'block';

      const searchLabel = document.createElement('label');
      searchLabel.textContent = 'Search Properties';
      searchLabel.className = 'block text-sm font-medium mb-1 text-white';
      searchLabel.setAttribute('for', 'propertiesSearch');

      const searchInput = document.createElement('input');
      searchInput.type = 'text';
      searchInput.id = 'propertiesSearch';
      searchInput.placeholder = 'Search properties...';
      searchInput.className = 'bg-gray-700 px-4 py-2 rounded text-white w-full';
      searchInput.setAttribute('aria-label', 'Search server properties');

      searchContainer.appendChild(searchLabel);
      searchContainer.appendChild(searchInput);

      const addButton = document.createElement('button');
      addButton.textContent = 'Add Property';
      addButton.type = 'button';
      addButton.className = 'mt-2 bg-blue-600 hover:bg-blue-700 text-white px-2 py-1 rounded text-xs';
      addButton.addEventListener('click', showCustomPropertyForm);
      searchContainer.appendChild(addButton);

      fieldsContainer.appendChild(searchContainer);

      searchInput.addEventListener('input', (e) => {
        renderPropertiesList(displayProperties, e.target.value);
      });

      elements.searchInput = searchInput;
    }

    let propertiesList = fieldsContainer.querySelector('#propertiesList');
    if (!propertiesList) {
      propertiesList = document.createElement('div');
      propertiesList.id = 'propertiesList';
      propertiesList.className = 'space-y-2';
      fieldsContainer.appendChild(propertiesList);
    }

    renderPropertiesList(properties, filter);

    const closeButton = elements.editPropertiesModal.querySelector('.close-button');
    if (closeButton && !closeButton.dataset.closeHandlerAdded) {
      closeButton.addEventListener('click', () => {
        elements.searchInput.value = '';
        renderPropertiesList(displayProperties, '');
        elements.editPropertiesModal.classList.add('hidden');
        hideCustomPropertyForm();
      });
      closeButton.dataset.closeHandlerAdded = 'true';
    }
  }

  function showCustomPropertyForm() {
    let formContainer = elements.propertiesFields.querySelector('#customPropertyForm');
    if (formContainer) {
      formContainer.remove();
    }

    formContainer = document.createElement('div');
    formContainer.id = 'customPropertyForm';
    formContainer.className = 'mb-4 p-4 bg-gray-800 rounded';

    const form = document.createElement('form');
    form.addEventListener('submit', (e) => e.preventDefault());

    const keyInput = document.createElement('input');
    keyInput.type = 'text';
    keyInput.placeholder = 'Property name';
    keyInput.className = 'bg-gray-700 px-4 py-2 rounded text-white w-full mb-2';

    const valueInput = document.createElement('input');
    valueInput.type = 'text';
    valueInput.placeholder = 'Property value';
    valueInput.className = 'bg-gray-700 px-4 py-2 rounded text-white w-full mb-2';

    const addButton = document.createElement('button');
    addButton.type = 'button';
    addButton.textContent = 'Add';
    addButton.className = 'bg-green-600 hover:bg-green-700 text-white px-2 py-1 rounded text-xs mr-2';
    addButton.addEventListener('click', () => {
      const key = keyInput.value.trim();
      const value = valueInput.value.trim();
      if (key && value) {
        displayProperties[key] = value;
        allProperties[key] = value;
        renderPropertiesList(displayProperties, elements.searchInput.value);
        formContainer.remove();
      } else {
        showNotification('Please enter both property name and value', 'error', 'custom-property-error');
      }
    });

    const cancelButton = document.createElement('button');
    cancelButton.type = 'button';
    cancelButton.textContent = 'Cancel';
    cancelButton.className = 'bg-gray-600 hover:bg-gray-700 text-white px-2 py-1 rounded text-xs';
    cancelButton.addEventListener('click', hideCustomPropertyForm);

    form.appendChild(keyInput);
    form.appendChild(valueInput);
    form.appendChild(addButton);
    form.appendChild(cancelButton);
    formContainer.appendChild(form);

    elements.propertiesFields.insertBefore(formContainer, elements.propertiesFields.querySelector('#propertiesList'));
  }

  function hideCustomPropertyForm() {
    const formContainer = elements.propertiesFields.querySelector('#customPropertyForm');
    if (formContainer) {
      formContainer.remove();
    }
  }

  function showDeleteConfirmationModal(key) {
    const modal = document.createElement('div');
    modal.id = 'deleteConfirmationModal';
    modal.className = 'absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';

    const modalContent = document.createElement('div');
    modalContent.className = 'bg-gray-800 p-6 rounded-lg max-w-md w-full';

    const header = document.createElement('h3');
    header.className = 'text-lg font-medium text-white mb-4';
    header.textContent = 'Confirm Deletion';

    const message = document.createElement('p');
    message.className = 'text-white mb-6';
    message.textContent = `Are you sure you want to delete the property "${key}"? This action cannot be undone.`;

    const buttonContainer = document.createElement('div');
    buttonContainer.className = 'flex justify-end space-x-2';

    const cancelButton = document.createElement('button');
    cancelButton.type = 'button';
    cancelButton.className = 'bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded';
    cancelButton.textContent = 'Cancel';
    cancelButton.addEventListener('click', () => modal.remove());

    const deleteButton = document.createElement('button');
    deleteButton.type = 'button';
    deleteButton.className = 'bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded';
    deleteButton.textContent = 'Delete';
    deleteButton.addEventListener('click', () => {
      delete displayProperties[key];
      delete allProperties[key];
      renderPropertiesList(displayProperties, elements.searchInput.value);
      modal.remove();
      showNotification(`Property "${key}" deleted`, 'success', 'delete-property-success');
    });

    buttonContainer.appendChild(cancelButton);
    buttonContainer.appendChild(deleteButton);
    modalContent.appendChild(header);
    modalContent.appendChild(message);
    modalContent.appendChild(buttonContainer);
    modal.appendChild(modalContent);

    elements.editPropertiesModal.appendChild(modal);
  }


  function renderPropertiesList(properties, filter = '') {
    const propertiesList = elements.propertiesFields.querySelector('#propertiesList');
    propertiesList.innerHTML = '';

    const filteredProperties = Object.entries(properties).filter(([key]) =>
      key.toLowerCase().includes(filter.toLowerCase())
    );

    filteredProperties.forEach(([key, value]) => {
      if (filteredSettings.includes(key)) {
        return;
      }
      const fieldDiv = document.createElement('div');
      fieldDiv.className = 'flex items-center space-x-2';
      fieldDiv.style.display = 'flex';

      const deleteButton = document.createElement('button');
      deleteButton.type = 'button';
      deleteButton.className = 'text-red-500 hover:text-red-700';
      deleteButton.innerHTML = '✕';
      deleteButton.title = `Delete ${key}`;
      deleteButton.addEventListener('click', () => showDeleteConfirmationModal(key));

      let inputType = 'text';
      let isBoolean = value.toLowerCase() === 'true' || value.toLowerCase() === 'false';
      if (isBoolean) {
        inputType = 'switch';
      } else if (/^\d+$/.test(value) && !isNaN(parseInt(value))) {
        inputType = 'number';
      }

      const label = document.createElement('label');
      label.textContent = key;
      label.className = 'w-1/3 text-sm font-medium text-white';
      label.setAttribute('for', `prop-${key}`);

      if (inputType === 'switch') {
        const hiddenInput = document.createElement('input');
        hiddenInput.type = 'text';
        hiddenInput.id = `prop-${key}`;
        hiddenInput.name = key;
        hiddenInput.value = value.toLowerCase();
        hiddenInput.style.display = 'none';

        const switchContainer = document.createElement('div');
        switchContainer.className = 'relative inline-block';
        switchContainer.setAttribute('role', 'switch');
        switchContainer.setAttribute('aria-checked', value.toLowerCase());
        switchContainer.dataset.name = key;
        switchContainer.style.width = '40px';
        switchContainer.style.height = '24px';
        switchContainer.style.display = 'inline-block';
        switchContainer.style.position = 'relative';
        switchContainer.style.cursor = 'pointer';
        switchContainer.style.zIndex = '10';

        const switchTrack = document.createElement('div');
        switchTrack.className = 'block w-full h-full rounded-full';
        switchTrack.style.backgroundColor = value.toLowerCase() === 'true' ? '#10B981' : '#4B5563';
        switchTrack.style.transition = 'background-color 0.2s ease-in-out';

        const switchHandle = document.createElement('div');
        switchHandle.className = 'absolute rounded-full bg-white';
        switchHandle.style.width = '16px';
        switchHandle.style.height = '16px';
        switchHandle.style.top = '4px';
        switchHandle.style.left = value.toLowerCase() === 'true' ? '20px' : '4px';
        switchHandle.style.transition = 'left 0.2s ease-in-out';
        switchHandle.style.position = 'absolute';
        switchHandle.style.zIndex = '11';

        const toggleSwitch = () => {
          const currentValue = hiddenInput.value === 'true';
          const newValue = !currentValue;
          hiddenInput.value = newValue.toString();
          switchContainer.setAttribute('aria-checked', newValue.toString());
          switchTrack.style.backgroundColor = newValue ? '#10B981' : '#4B5563';
          switchHandle.style.left = newValue ? '20px' : '4px';
        };

        switchContainer.addEventListener('click', toggleSwitch);
        switchContainer.addEventListener('keydown', (e) => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            toggleSwitch();
          }
        });

        switchContainer.appendChild(switchTrack);
        switchContainer.appendChild(switchHandle);
        fieldDiv.appendChild(deleteButton);
        fieldDiv.appendChild(label);
        fieldDiv.appendChild(hiddenInput);
        fieldDiv.appendChild(switchContainer);
      } else {
        const input = document.createElement('input');
        input.id = `prop-${key}`;
        input.name = key;
        input.className = 'bg-gray-700 px-4 py-2 rounded text-white w-2/3';
        input.type = inputType;
        input.value = value;
        if (inputType === 'number') {
          input.min = '0';
        }
        fieldDiv.appendChild(deleteButton);
        fieldDiv.appendChild(label);
        fieldDiv.appendChild(input);
      }

      propertiesList.appendChild(fieldDiv);
    });
  }

  function propertiesToString(properties) {
    let header = `#Minecraft server properties\n#${new Date().toUTCString()}\n`;
    return header + Object.entries(properties)
      .map(([key, value]) => `${key}=${value}`)
      .join('\n');
  }

  async function fetchServerProperties() {
    try {
      const key = `action-fetch-properties`;
      const response = await wsRequest('/server-properties', 'GET');
      if (response.error) {
        updateNotification(notification, `Failed to load server properties: ${response.error}`, 'error', key);
        return;
      }
      if (response.content && response.content.length > 4000) {
        updateNotification(notification, `Server properties file is too large to edit (${response.content.length} characters, max 4000)`, 'error', key);
        return;
      }
      allProperties = parseServerProperties(response.content || '');
      displayProperties = Object.fromEntries(
        Object.entries(allProperties).filter(([key]) => !filteredSettings.includes(key))
      );
      renderPropertiesFields(displayProperties);
      elements.editPropertiesModal.classList.remove('hidden');
    } catch (error) {
      console.error('Fetch server properties error:', error);
      showNotification(`Failed to load server properties: ${error.message}`, 'error', 'fetch-properties-error');
    }
  }

  async function saveServerProperties() {
    try {
      const key = `action-save-properties`;
      const properties = {};
      const inputs = elements.propertiesFields.querySelectorAll('input:not(#propertiesSearch):not([id="customPropertyKey"]):not([id="customPropertyValue"])');

      inputs.forEach(input => {
        const key = input.name;
        let value = input.value.trim();
        if (value !== '') {
          properties[key] = value;
        }
      });

      const fullProperties = { ...allProperties, ...properties };
      const content = propertiesToString(fullProperties);
      const response = await wsRequest('/server-properties', 'POST', { content });
      if (response.error) {
        updateNotification(notification, `Failed to save server properties: ${response.error}`, 'error', key);
        return;
      }
      if (elements.searchInput) {
        elements.searchInput.value = '';
        renderPropertiesList(displayProperties, '');
      }
      elements.editPropertiesModal.classList.add('hidden');
    } catch (error) {
      console.error('Save server properties error:', error);
      showNotification(`Failed to save server properties: ${error.message}`, 'error', 'save-properties-error');
    }
  }

  async function updateMods() {
    try {
      const key = `action-update-mods`;
      const response = await wsRequest('/update-mods', 'POST');
      if (response.error) {
        elements.updateModsOutput.textContent = `Error: ${response.error}`;
        showNotification(`Failed to update mods: ${response.error}`, 'error', key);
      } else {
        const output = response.output || 'No output from mod update.';
        elements.updateModsOutput.textContent = output;
      }
      elements.updateModsModal.classList.remove('hidden');
    } catch (error) {
      console.error('Update mods error:', error);
      elements.updateModsOutput.textContent = `Error: ${error.message}`;
      elements.updateModsModal.classList.remove('hidden');
      showNotification(`Failed to update mods: ${error.message}`, 'error', 'update-mods-error');
    }
  }

  async function createBackup() {
    try {
      const key = `action-backup`;
      const notification = showNotification('Creating backup... Download will start when ready.', 'loading', key);
      const response = await wsRequest('/backup', 'POST');
      if (response.error) {
        updateNotification(notification, `Failed to create backup: ${response.error}`, 'error', key);
        return;
      }
      const downloadURL = response.downloadURL;
      if (downloadURL) {
        const link = document.createElement('a');
        link.href = downloadURL;
        link.download = '';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        updateNotification(notification, 'Backup created and download started', 'success', key);
      } else {
        updateNotification(notification, 'Backup created but download URL unavailable', 'error', key);
      }
    } catch (error) {
      console.error('Create backup error:', error);
      showNotification(`Failed to create backup: ${error.message}`, 'error', 'backup-error');
    }
  }

  async function connectSftp() {
    // if (!isSftpOnline) {
    //   showNotification('SFTP is offline. Please try again later.', 'error', 'sftp-offline');
    //   return;
    // }

    if (!sftpCredentials) {
      showNotification('SFTP credentials not available.', 'error', 'sftp-credentials');
      return;
    }

    try {
      const key = `action-sftp-connect`;
      const notification = showNotification('Connecting to SFTP...', 'loading', key);
      const response = await fetch('https://sftp.my-mc.link/auto-connection', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          host: sftpCredentials.hostname.replace('sftp://', ''),
          port: sftpCredentials.port,
          username: sftpCredentials.user,
          password: sftpCredentials.password,
        }),
      });

      const result = await response.json();
      if (result.success && result.connectionUrl) {
        elements.sftpIframe.src = result.connectionUrl;
        elements.sftpBrowserSection.style.display = 'block';
        updateNotification(notification, 'SFTP connected successfully', 'success', key);
      } else {
        updateNotification(notification, 'Failed to establish SFTP connection.', 'error', key);
      }
    } catch (error) {
      console.error('SFTP connection error:', error);
      showNotification(`Failed to connect to SFTP: ${error.message}`, 'error', 'sftp-connect-error');
    }
  }

  elements.loginBtn.addEventListener('click', () => {
    apiKey = elements.loginApiKey.value.trim();
    if (apiKey) {
      localStorage.setItem('apiKey', apiKey);
      elements.loginError.classList.add('hidden');
      connectWebSocket();
    } else {
      elements.loginError.classList.remove('hidden');
      elements.loginError.textContent = 'Please enter an API key.';
    }
  });

  // elements.apiKeyInput.addEventListener('change', handleApiKeyChange);

  elements.generateMyLinkBtn.addEventListener('click', async () => {
    try {
      const key = `action-my-link`;
      await wsRequest('/my-link');
      showNotification('Connection link generated successfully', 'success', key);
    } catch (error) {
      console.error('Generate connection link error:', error);
      showNotification(`Failed to generate connection link: ${error.message}`, 'error', 'my-link-error');
    }
  });

  elements.generateGeyserLinkBtn.addEventListener('click', async () => {
    try {
      const key = `action-my-geyser-link`;
      await wsRequest('/my-geyser-link');
      showNotification('Geyser link generated successfully', 'success', key);
    } catch (error) {
      console.error('Generate geyser link error:', error);
      showNotification(`Failed to generate Geyser link: ${error.message}`, 'error', 'geyser-link-error');
    }
  });

  elements.generateSftpLinkBtn.addEventListener('click', async () => {
    try {
      const key = `action-my-sftp`;
      await wsRequest('/my-sftp');
      showNotification('SFTP link generated successfully', 'success', key);
    } catch (error) {
      console.error('Generate SFTP link error:', error);
      showNotification(`Failed to generate SFTP link: ${error.message}`, 'error', 'sftp-link-error');
    }
  });

  elements.sftpBtn.addEventListener('click', connectSftp);

  document.getElementById('refresh').addEventListener('click', async () => {
    if (ws && ws.readyState === WebSocket.OPEN) {
      const key = `action-refresh`;
      const notification = showNotification('Refreshing server data...', 'loading', key);
      ws.send(JSON.stringify({ type: 'refresh' }));
      initializeTerminal();
      setTimeout(() => updateNotification(notification, 'Server data refreshed successfully', 'success', key), 1000);
    } else {
      showNotification('Not connected to server. Please log in.', 'error', 'ws-disconnected');
    }
  });

  document.getElementById('startBtn').addEventListener('click', async () => {
    try {
      const key = `action-start`;
      const notification = showNotification('Starting server...', 'loading', key);
      await wsRequest('/start');
      initializeTerminal();
      if (ws && ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] }));
        const messageHandler = (event) => {
          try {
            const message = JSON.parse(event.data);
            if (message.type === 'docker') {
              state.serverStatus = message.data?.status || 'Unknown';
              elements.serverStatus.textContent = state.serverStatus;
              toggleSections(state.serverStatus);
              if (message.data?.status.toLowerCase() === 'running') {
                updateNotification(notification, 'Server started successfully', 'success', key);
                // Ensure restart button is enabled
                if (elements.restartBtn) {
                  elements.restartBtn.disabled = false;
                  elements.restartBtn.classList.remove('disabled-btn');
                }
                ws.removeEventListener('message', messageHandler);
              }
            }
          } catch (error) {
            console.error('Error parsing WebSocket message:', error);
          }
        };
        ws.addEventListener('message', messageHandler);
        setTimeout(() => {
          if (ws && ws.readyState === WebSocket.OPEN) {
            ws.removeEventListener('message', messageHandler);
            if (state.serverStatus.toLowerCase() !== 'running') {
              updateNotification(notification, 'Failed to start server. Please try again.', 'error', key);
              toggleSections(state.serverStatus);
            }
          }
        }, 30000);
      } else {
        updateNotification(notification, 'Not connected to server. Please log in.', 'error', key);
      }
    } catch (error) {
      console.error('Start server error:', error);
      showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error');
    }
  });


  document.getElementById('stopBtn').addEventListener('click', async () => {
    try {
      const key = `action-stop`;
      const notification = showNotification('Stopping server...', 'loading', key);
      await wsRequest('/stop');
      updateNotification(notification, 'Server stopped successfully', 'success', key);
    } catch (error) {
      console.error('Stop server error:', error);
      showNotification(`Failed to stop server: ${error.message}`, 'error', 'stop-error');
    }
  });

  document.getElementById('restartBtn').addEventListener('click', async () => {
    try {
      const key = `action-restart`;
      const notification = showNotification('Restarting server...', 'loading', key);
      await wsRequest('/restart');
      initializeTerminal();
      if (ws && ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] }));
        const messageHandler = (event) => {
          try {
            const message = JSON.parse(event.data);
            if (message.type === 'docker') {
              state.serverStatus = message.data?.status || 'Unknown';
              elements.serverStatus.textContent = state.serverStatus;
              toggleSections(state.serverStatus);
              if (message.data?.status === 'running') {
                updateNotification(notification, 'Server restarted successfully', 'success', key);
                ws.removeEventListener('message', messageHandler);
              }
            }
          } catch (error) {
            console.error('Error parsing WebSocket message:', error);
          }
        };
        ws.addEventListener('message', messageHandler);
        setTimeout(() => {
          if (ws && ws.readyState === WebSocket.OPEN) {
            ws.removeEventListener('message', messageHandler);
            if (state.serverStatus !== 'running') {
              updateNotification(notification, 'Failed to restart server. Please try again.', 'error', key);
              toggleSections(state.serverStatus);
            }
          }
        }, 60000);
      } else {
        updateNotification(notification, 'Not connected to server. Please log in.', 'error', key);
      }
    } catch (error) {
      console.error('Restart server error:', error);
      showNotification(`Failed to restart server: ${error.message}`, 'error', 'restart-error');
    }
  });



  elements.updateModsBtn.addEventListener('click', updateMods);

  elements.closeUpdateModsBtn.addEventListener('click', () => {
    elements.updateModsModal.classList.add('hidden');
    elements.updateModsOutput.textContent = '';
  });

  elements.updateModsModal.querySelector('.modal-close').addEventListener('click', () => {
    elements.updateModsModal.classList.add('hidden');
    elements.updateModsOutput.textContent = '';
  });

  elements.backupBtn.addEventListener('click', createBackup);

  document.getElementById('searchBtn').addEventListener('click', () => {
    searchMods(1);
  });

  document.getElementById('sendConsole').addEventListener('click', sendConsoleCommand);

  elements.closeSearchBtn.addEventListener('click', closeSearch);

  elements.tellModal.querySelector('.modal-close').addEventListener('click', () => {
    elements.tellModal.classList.add('hidden');
  });

  elements.giveModal.querySelector('.modal-close').addEventListener('click', () => {
    elements.giveModal.classList.add('hidden');
  });

  elements.teleportModal.querySelector('.modal-close').addEventListener('click', () => {
    elements.teleportModal.classList.add('hidden');
  });

  elements.effectModal.querySelector('.modal-close').addEventListener('click', () => {
    elements.effectModal.classList.add('hidden');
  });

  elements.loadoutSelect.addEventListener('change', () => {
    const isCustom = elements.loadoutSelect.value === 'custom';
    elements.customGiveFields.classList.toggle('hidden', !isCustom);
    if (isCustom) {
      resetItemFields();
    }
  });

  elements.tellMessage.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      sendTellMessage();
    }
  });

  elements.itemList.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' && (e.target.classList.contains('item-name') || e.target.classList.contains('item-amount'))) {
      e.preventDefault();
      sendGiveCommand();
    }
  });

  elements.teleportForm.addEventListener('submit', (e) => {
    e.preventDefault();
    sendTeleportCommand();
  });

  elements.effectForm.addEventListener('submit', (e) => {
    e.preventDefault();
    sendEffectCommand();
  });

  elements.tellForm.addEventListener('submit', (e) => {
    e.preventDefault();
    sendTellMessage();
  });

  elements.giveForm.addEventListener('submit', (e) => {
    e.preventDefault();
    sendGiveCommand();
  });

  elements.addItemBtn.addEventListener('click', addItemField);

  elements.editPropertiesBtn.addEventListener('click', fetchServerProperties);

  elements.editPropertiesModal.querySelector('.modal-close').addEventListener('click', () => {
    elements.editPropertiesModal.classList.add('hidden');
  });

  elements.editPropertiesForm.addEventListener('submit', (e) => {
    e.preventDefault();
    saveServerProperties();
  });

  elements.clearModListSearch.addEventListener('click', clearModListSearch);

  const debouncedModListSearch = debounce((query) => {
    modListSearchQuery = query.trim();
    modListCurrentPage = 1;
    elements.clearModListSearch.classList.toggle('hidden', !modListSearchQuery);
    renderModList();
  }, 300);

  elements.modListSearch.addEventListener('input', (e) => {
    debouncedModListSearch(e.target.value);
  });

  if (apiKey) {
    connectWebSocket();
  } else {
    showLoginPage();
  }
  window.showNotification = showNotification;

  // Add this at the end of the document.addEventListener('DOMContentLoaded', ...) block
  function applyResponsiveStyles() {
    const sections = document.querySelectorAll('.section-bg');
    sections.forEach(section => {
      section.style.padding = window.innerWidth <= 640 ? '1rem' : window.innerWidth <= 768 ? '1.5rem' : '2rem';
      section.style.maxWidth = '100%';
      section.style.overflowX = 'hidden';
    });

    const iframes = document.querySelectorAll('#sftpIframe');
    iframes.forEach(iframe => {
      iframe.style.height = window.innerWidth <= 640 ? '300px' : window.innerWidth <= 768 ? '400px' : '650px';
      iframe.style.minHeight = iframe.style.height;
      iframe.style.width = '100%';
      iframe.style.maxWidth = '100%';
    });

    const canvases = document.querySelectorAll('#memoryMeter, #cpuMeter');
    canvases.forEach(canvas => {
      canvas.style.width = window.innerWidth <= 640 ? '80px' : window.innerWidth <= 768 ? '100px' : '150px';
      canvas.style.height = canvas.style.width;
    });

    const terminals = document.querySelectorAll('#dockerLogsTerminal');
    terminals.forEach(terminal => {
      terminal.style.maxHeight = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem';
    });

    const consoles = document.querySelectorAll('#consoleOutput');
    consoles.forEach(console => {
      console.style.height = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem';
    });
  }

  window.addEventListener('resize', applyResponsiveStyles);

  sections.forEach(section => {
    section.style.transform = 'translateY(30px)';
    section.style.opacity = '0';
    section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out';
    observer.observe(section);
});

particlesJS("particles-js", {
  "particles": {
      "number": {
          "value": 30,
          "density": {
              "enable": true,
              "value_area": 800
          }
      },
      "color": {
          "value": ["#14b8a6", "#3b82f6"] // Mimics gradient by alternating colors
      },
      "shape": {
          "type": "circle", // Matches border-radius: 50%
          "stroke": {
              "width": 0,
              "color": "#000000"
          }
      },
      "opacity": {
          "value": 0.9, // Matches box-shadow opacity
          "random": true,
          "anim": {
              "enable": true, // Mimics fadeInOut animation
              "speed": 1, // Slower for smooth fade
              "opacity_min": 0, // Fades to fully transparent
              "sync": false
          }
      },
      "size": {
          "value": 8, // Default size (matches 8px)
          "random": true, // Allows some particles to be larger (up to 12px)
          "anim": {
              "enable": true,
              "speed": 4,
              "size_min": 4, // Smaller sizes for variation
              "sync": false
          }
      },
      "line_linked": {
          "enable": false // No lines needed per CSS
      },
      "move": {
          "enable": true,
          "speed": 2, // Mimics float animation
          "direction": "none",
          "random": true,
          "straight": false,
          "out_mode": "out",
          "bounce": false,
          "attract": {
              "enable": false
          }
      }
  },
  "interactivity": {
      "detect_on": "canvas",
      "events": {
          "onhover": {
              "enable": true,
              "mode": "repulse"
          },
          "onclick": {
              "enable": true,
              "mode": "push"
          },
          "resize": true
      },
      "modes": {
          "repulse": {
              "distance": 100,
              "duration": 0.4
          },
          "push": {
              "particles_nb": 4
          }
      }
  },
  "retina_detect": true
});

// Custom logic for glow effect
document.addEventListener('DOMContentLoaded', () => {
  const pJS = window.pJSDom[0].pJS;
  const targetElements = document.querySelectorAll('.feature-card, .nav-btn, .btn-minecraft');

  // Function to check if a particle is behind or near an element
  function checkParticleProximity() {
      targetElements.forEach(element => {
          const rect = element.getBoundingClientRect();
          let hasGlow = false;

          pJS.particles.array.forEach(particle => {
              const particleX = particle.x + pJS.canvas.el.offsetLeft;
              const particleY = particle.y + pJS.canvas.el.offsetTop;
              const buffer = 20; // Buffer zone around element for glow trigger

              // Check if particle is within or near the element's bounding box
              if (
                  particleX >= rect.left - buffer &&
                  particleX <= rect.right + buffer &&
                  particleY >= rect.top - buffer &&
                  particleY <= rect.bottom + buffer
              ) {
                  hasGlow = true;
              }
          });

          // Apply or remove glow effect
          if (hasGlow) {
              element.classList.add('glow-effect');
              element.classList.remove('no-glow');
          } else {
              element.classList.remove('glow-effect');
              element.classList.add('no-glow');
          }
      });
  }

  // Run proximity check in a separate animation loop
  function animateGlowEffect() {
      checkParticleProximity();
      requestAnimationFrame(animateGlowEffect);
  }

  // Start the animation loop
  animateGlowEffect();
});



});