import { URLSearchParams } from 'url';
import { getContainerStats, streamContainerLogs, readServerProperties, writeServerProperties, updateMods, createBackup } from './docker.js';
import { checkConnectionStatus, checkGeyserStatus, checkSftpStatus } from './status.js';
import { apiRequest } from './api.js';

const clients = new Map();
const staticEndpoints = ['log', 'website', 'map', 'my-link-cache', 'my-geyser-cache', 'my-sftp-cache', 'my-link', 'my-geyser-link', 'my-sftp', 'holesail-hashes', 'internal-sftp'];
const dynamicEndpoints = ['hello', 'time', 'mod-list'];

// Helper function to start Docker stats interval
function startDockerStatsInterval(ws, client, user, docker) {
  if (!client.subscriptions.has('docker') || user === 'Unknown') {
    console.log(`Skipping docker stats interval: ${user === 'Unknown' ? 'User unknown' : 'Not subscribed to docker'}`);
    return null;
  }

  // Send initial stats immediately
  (async () => {
    try {
      const initialStats = await getContainerStats(docker, user);
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: 'docker', data: { ...initialStats, user } }));
      }
    } catch (error) {
      console.error(`Error sending initial docker stats for ${user}:`, error.message);
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: 'docker', error: `Failed to fetch initial stats: ${error.message}` }));
      }
    }
  })();

  // Start interval for periodic stats
  const intervalId = setInterval(async () => {
    try {
      if (ws.readyState !== ws.OPEN) {
        console.warn(`WebSocket not open (state: ${ws.readyState}) for ${user}, clearing docker stats interval ${intervalId}`);
        clearInterval(intervalId);
        client.intervals = client.intervals.filter(id => id !== intervalId);
        return;
      }

      const container = docker.getContainer(user);
      const inspect = await container.inspect();
      if (inspect.State.Status !== 'running') {
        ws.send(JSON.stringify({ type: 'docker', error: `Container ${user} is not running` }));
        return;
      }

      const stats = await getContainerStats(docker, user);
      if (stats.error) {
        console.error(`Error fetching stats for ${user}: ${stats.error}`);
        ws.send(JSON.stringify({ type: 'docker', error: stats.error }));
      } else {
        ws.send(JSON.stringify({ type: 'docker', data: { ...stats, user } }));
      }
    } catch (error) {
      console.error(`Error in docker stats interval for ${user}:`, error.message);
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: 'docker', error: `Failed to fetch stats: ${error.message}` }));
      }
    }
  }, 1000); // 1-second interval

  client.intervals.push(intervalId);
  console.log(`Docker stats interval ID ${intervalId} added for ${user}`);

  // Test interval to verify setInterval execution
  const testIntervalId = setInterval(() => {
    // console.log(`Test interval tick for ${user} at ${new Date().toISOString()}, Interval ID: ${testIntervalId}`);
  }, 2000); // 2-second test interval
  client.intervals.push(testIntervalId);
  // console.log(`Test interval ID ${testIntervalId} added for ${user}`);

  return intervalId;
}

async function fetchAndSendUpdate(ws, endpoint, client, docker) {
  if (['mod-list', 'list-players'].includes(endpoint) && client.user !== 'Unknown') {
    try {
      const container = docker.getContainer(client.user);
      const inspect = await container.inspect();
      if (inspect.State.Status !== 'running') {
        console.warn(`Container ${client.user} is not running for endpoint ${endpoint}`);
        ws.send(JSON.stringify({ type: endpoint, error: `Container ${client.user} is not running` }));
        return;
      }
    } catch (error) {
      console.error(`Failed to check container status for ${endpoint} for ${client.user}:`, error.message);
      ws.send(JSON.stringify({ type: endpoint, error: `Failed to check container status: ${error.message}` }));
      return;
    }
  }

  if (endpoint === 'time' && client.cache['time']) {
    ws.send(JSON.stringify({ type: endpoint, data: client.cache['time'] }));
    return;
  }

  if (endpoint === 'holesail-hashes' && client.cache['holesail-hashes']) {
    ws.send(JSON.stringify({ type: endpoint, data: client.cache['holesail-hashes'] }));
    return;
  }

  if (endpoint === 'internal-sftp' && client.cache['internal-sftp']) {
    console.log(`Using cached internal-sftp data for ${client.user}`);
    ws.send(JSON.stringify({ type: 'internal-sftp', data: client.cache['internal-sftp'] }));
    return;
  }

  if (endpoint === 'holesail-hashes') {
    try {
      const [hashResponse, geyserHashResponse, sftpHashResponse] = await Promise.all([
        apiRequest('/my-hash', client.apiKey),
        apiRequest('/my-geyser-hash', client.apiKey),
        apiRequest('/my-sftp-hash', client.apiKey)
      ]);

      const response = {
        myHash: hashResponse.success ? hashResponse.message : null,
        geyserHash: geyserHashResponse.success ? geyserHashResponse.message : null,
        sftpHash: sftpHashResponse.success ? sftpHashResponse.message : null,
        errors: []
      };

      if (!hashResponse.success) response.errors.push(`my-hash: ${hashResponse.message || 'Failed to fetch'}`);
      // if (!geyserHashResponse.success) response.errors.push(`my-geyser-hash: ${geyserHashResponse.message || 'Failed to fetch'}`);
      // if (!sftpHashResponse.success) response.errors.push(`my-sftp-hash: ${sftpHashResponse.message || 'Failed to fetch'}`);

      client.cache['holesail-hashes'] = response;

      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: endpoint, data: response }));
      }
    } catch (error) {
      console.error(`Error fetching holesail-hashes for ${client.user}:`, error.message);
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: endpoint, error: `Failed to fetch holesail hashes: ${error.message}` }));
      }
    }
    return;
  }

  try {
    const response = await apiRequest(`/${endpoint}`, client.apiKey);
    if (!response.error) {
      if (endpoint === 'time') client.cache['time'] = response;
      if (endpoint === 'my-link-cache') {
        client.cache['my-link-cache'] = response;
        if (client.subscriptions.has('my-link-cache') && client.user !== 'Unknown') {
          try {
            const container = docker.getContainer(client.user);
            const inspect = await container.inspect();
            if (inspect.State.Status === 'running' && response.hostname && response.port) {
              const status = await checkConnectionStatus(response.hostname, response.port);
              ws.send(JSON.stringify({ type: 'connection-status', data: { isOnline: status.isOnline } }));
            } else {
              ws.send(JSON.stringify({ type: 'connection-status', error: `Container ${client.user} is not running` }));
            }
          } catch (error) {
            console.error(`Error checking connection status for ${client.user}:`, error.message);
            ws.send(JSON.stringify({ type: 'connection-status', error: `Failed to check container status: ${error.message}` }));
          }
        }
      }
      if (endpoint === 'my-geyser-cache') {
        client.cache['my-geyser-cache'] = response;
        if (client.subscriptions.has('my-geyser-cache') && client.user !== 'Unknown') {
          try {
            const container = docker.getContainer(client.user);
            const inspect = await container.inspect();
            if (inspect.State.Status === 'running' && response.hostname && response.port) {
              const status = await checkGeyserStatus(response.hostname, response.port);
              ws.send(JSON.stringify({ type: 'geyser-status', data: { isOnline: status.isOnline } }));
            } else {
              ws.send(JSON.stringify({ type: 'geyser-status', error: `Container ${client.user} is not running` }));
            }
          } catch (error) {
            console.error(`Error checking geyser status for ${client.user}:`, error.message);
            ws.send(JSON.stringify({ type: 'geyser-status', error: `Failed to check container status: ${error.message}` }));
          }
        }
      }
      if (endpoint === 'my-sftp-cache') {
        client.cache['my-sftp-cache'] = response;
        if (client.subscriptions.has('my-sftp-cache') && client.user !== 'Unknown') {
          try {
            const container = docker.getContainer(client.user);
            const inspect = await container.inspect();
            const ipAddress = inspect.NetworkSettings.Networks?.minecraft_network?.IPAddress || 'N/A';
            if (inspect.State.Status === 'running' && response.hostname && response.port) {
              const status = await checkSftpStatus(response.hostname, response.port);
              ws.send(JSON.stringify({
                type: 'sftp-status',
                data: {
                  isOnline: status.isOnline,
                  ipAddress
                }
              }));
            } else {
              ws.send(JSON.stringify({
                type: 'sftp-status',
                error: `Container ${client.user} is not running`,
                ipAddress
              }));
            }
            response.ipAddress = ipAddress;
          } catch (error) {
            console.error(`Error checking sftp status for ${client.user}:`, error.message);
            ws.send(JSON.stringify({
              type: 'sftp-status',
              error: `Failed to check container status: ${error.message}`
            }));
          }
        }
      }
      if (endpoint === 'internal-sftp') {
        client.cache['internal-sftp'] = response;
      }
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: endpoint, data: response }));
      }
    } else {
      console.error(`API error for /${endpoint}: ${response.error}`);
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: endpoint, error: response.error }));
      }
    }
  } catch (error) {
    console.error(`Error fetching /${endpoint} for ${client.user}:`, error.message);
    if (ws.readyState === ws.OPEN) {
      ws.send(JSON.stringify({ type: endpoint, error: `Failed to fetch ${endpoint}: ${error.message}` }));
    }
  }
}

async function manageStatusChecks(ws, client, user, docker) {
  try {
    const container = docker.getContainer(user);
    const inspect = await container.inspect();
    const isRunning = inspect.State.Status === 'running';

    // Clear only status check intervals to prevent duplicates
    ['connectionStatusInterval', 'geyserStatusInterval', 'sftpStatusInterval', 'statusCheckMonitorInterval'].forEach((key) => {
      if (client[key]) {
        console.log(`Clearing ${key} for ${user}`);
        clearInterval(client[key]);
        client[key] = null;
        client.intervals = client.intervals.filter(id => id !== client[key]);
      }
    });

    if (!isRunning || user === 'Unknown') {
      ['my-link-cache', 'my-geyser-cache', 'my-sftp-cache', 'internal-sftp'].forEach((sub) => {
        if (client.subscriptions.has(sub)) {
          const statusType = sub.replace('-cache', '-status');
          console.warn(`Container ${user} is not running or user unknown for subscription ${sub}`);
          ws.send(JSON.stringify({ type: statusType, error: `Container ${user} is not running or user unknown` }));
        }
      });
      if (!isRunning && (client.subscriptions.has('my-link-cache') || client.subscriptions.has('my-geyser-cache') || client.subscriptions.has('my-sftp-cache') || client.subscriptions.has('internal-sftp')) && user !== 'Unknown') {
        console.log(`Starting container status monitor for ${user}`);
        client.statusCheckMonitorInterval = setInterval(async () => {
          try {
            const monitorContainer = docker.getContainer(user);
            const monitorInspect = await monitorContainer.inspect();
            if (monitorInspect.State.Status === 'running') {
              console.log(`Container ${user} is running, restarting status checks`);
              await manageStatusChecks(ws, client, user, docker);
              clearInterval(client.statusCheckMonitorInterval);
              client.statusCheckMonitorInterval = null;
            }
          } catch (error) {
            console.error(`Error monitoring container ${user}:`, error.message);
          }
        }, parseInt(process.env.CONTAINER_STATUS_MONITOR_INTERVAL_MS, 10));
        client.intervals.push(client.statusCheckMonitorInterval);
      }
      return;
    }

    const statusChecks = [
      {
        subscription: 'my-link-cache',
        intervalKey: 'connectionStatusInterval',
        intervalMs: process.env.CONNECTION_STATUS_INTERVAL_MS,
        checkFn: checkConnectionStatus,
        cacheKey: 'my-link-cache',
        statusType: 'connection-status'
      },
      {
        subscription: 'my-geyser-cache',
        intervalKey: 'geyserStatusInterval',
        intervalMs: process.env.GEYSER_STATUS_INTERVAL_MS,
        checkFn: checkGeyserStatus,
        cacheKey: 'my-geyser-cache',
        statusType: 'geyser-status'
      },
      {
        subscription: 'my-sftp-cache',
        intervalKey: 'sftpStatusInterval',
        intervalMs: process.env.SFTP_STATUS_INTERVAL_MS,
        checkFn: checkSftpStatus,
        cacheKey: 'my-sftp-cache',
        statusType: 'sftp-status'
      }
    ];

    for (const { subscription, intervalKey, intervalMs, checkFn, cacheKey, statusType } of statusChecks) {
      if (client.subscriptions.has(subscription)) {
        console.log(`Starting ${statusType} check for ${user}`);
        client[intervalKey] = setInterval(async () => {
          try {
            const containerCheck = docker.getContainer(user);
            const inspectCheck = await containerCheck.inspect();
            if (inspectCheck.State.Status !== 'running') {
              console.log(`Container ${user} stopped, clearing ${statusType} interval`);
              clearInterval(client[intervalKey]);
              client[intervalKey] = null;
              client.intervals = client.intervals.filter(id => id !== client[intervalKey]);
              return;
            }
            const data = client.cache[cacheKey];
            if (data && data.hostname && data.port) {
              const status = await checkFn(data.hostname, data.port);
              if (ws.readyState === ws.OPEN) {
                ws.send(JSON.stringify({ type: statusType, data: { isOnline: status.isOnline } }));
              }
            }
          } catch (error) {
            console.error(`Error in ${statusType} check for ${user}:`, error.message);
            if (ws.readyState === ws.OPEN) {
              ws.send(JSON.stringify({ type: statusType, data: { isOnline: false, error: error.message } }));
            }
          }
        }, parseInt(intervalMs, 10));
        client.intervals.push(client[intervalKey]);

        const data = client.cache[cacheKey];
        if (data && data.hostname && data.port) {
          console.log(`Performing initial ${statusType} check for ${user}`);
          const status = await checkFn(data.hostname, data.port);
          if (ws.readyState === ws.OPEN) {
            ws.send(JSON.stringify({ type: statusType, data: { isOnline: status.isOnline } }));
          }
        }
      }
    }
  } catch (error) {
    console.error(`Error managing status checks for ${user}:`, error.message);
  }
}

export function handleWebSocket(ws, req, docker) {
  const urlParams = new URLSearchParams(req.url.split('?')[1]);
  const apiKey = urlParams.get('apiKey');
  if (!apiKey) {
    console.error('WebSocket connection rejected: Missing API key');
    ws.send(JSON.stringify({ error: 'API key required' }));
    ws.close();
    return;
  }

  const client = {
    apiKey,
    subscriptions: new Set(),
    user: null,
    intervals: [],
    logStream: null,
    cache: {},
    connectionStatusInterval: null,
    geyserStatusInterval: null,
    sftpStatusInterval: null,
    statusCheckMonitorInterval: null,
    lastUpdateUserTime: 0 // For debouncing updateUser
  };
  clients.set(ws, client);
  console.log('WebSocket client registered with API key');

  // Heartbeat to keep WebSocket alive
  const heartbeatInterval = setInterval(() => {
    if (ws.readyState === ws.OPEN) {
      ws.ping();
      console.log(`Sent ping to client for user ${client.user || 'unknown'}`);
    } else {
      console.log(`WebSocket not open (state: ${ws.readyState}), stopping heartbeat for user ${client.user || 'unknown'}`);
      clearInterval(heartbeatInterval);
    }
  }, 30000);

  ws.on('pong', () => {
    console.log(`Received pong from client for user ${client.user || 'unknown'}`);
  });

  // Send internal-sftp data immediately on connection if subscribed
  (async () => {
    try {
      if (client.subscriptions.has('internal-sftp')) {
        await fetchAndSendUpdate(ws, 'internal-sftp', client, docker);
      }
    } catch (error) {
      console.error('Error sending initial internal-sftp data:', error.message);
      if (ws.readyState === ws.OPEN) {
        ws.send(JSON.stringify({ type: 'internal-sftp', error: `Failed to fetch initial internal-sftp data: ${error.message}` }));
      }
    }
  })();

  ws.on('message', async (message) => {
    try {
      const data = JSON.parse(message.toString());
      console.log('WebSocket message received:', data.type);

      if (data.type === 'subscribe') {
        data.endpoints.forEach(endpoint => {
          client.subscriptions.add(endpoint);
          console.log(`Client subscribed to ${endpoint}`);
        });
        console.log(`Client subscriptions: ${Array.from(client.subscriptions)}`);

        // Send internal-sftp data immediately after subscription
        if (client.subscriptions.has('internal-sftp')) {
          try {
            await fetchAndSendUpdate(ws, 'internal-sftp', client, docker);
          } catch (error) {
            console.error(`Error fetching internal-sftp data after subscription for ${client.user}:`, error.message);
            if (ws.readyState === ws.OPEN) {
              ws.send(JSON.stringify({ type: 'internal-sftp', error: `Failed to fetch internal-sftp data: ${error.message}` }));
            }
          }
        }

        let hello = client.cache['hello'] || await apiRequest('/hello', client.apiKey);
        if (!client.cache['hello'] && !hello.error) client.cache['hello'] = hello;

        if (hello.error) {
          console.error('Failed to fetch /hello:', hello.error);
          ws.send(JSON.stringify({ type: 'hello', error: hello.error }));
          return;
        }

        if (hello.message && typeof hello.message === 'string') {
          const user = hello.message.split(', ')[1]?.replace('!', '').trim() || 'Unknown';
          client.user = user;
          console.log(`User identified: ${user}`);
          ws.send(JSON.stringify({ type: 'hello', data: hello }));

          // Start Docker stats interval
          startDockerStatsInterval(ws, client, user, docker);

          if (client.subscriptions.has('docker-logs') && user !== 'Unknown') {
            console.log(`Starting docker logs stream for ${user}`);
            await streamContainerLogs(docker, ws, user, client);
          } else if (user === 'Unknown') {
            console.warn('Cannot start docker logs stream: User is Unknown');
            ws.send(JSON.stringify({ type: 'docker-logs', error: 'User not identified' }));
          }

          await manageStatusChecks(ws, client, user, docker);

          await Promise.all([
            ...staticEndpoints.filter(e => client.subscriptions.has(e)).map(e => fetchAndSendUpdate(ws, e, client, docker)),
            ...dynamicEndpoints.filter(e => client.subscriptions.has(e)).map(async (e) => {
              if (e === 'hello' && client.cache['hello']) {
                ws.send(JSON.stringify({ type: 'hello', data: client.cache['hello'] }));
                return;
              }
              if (e === 'time' && client.cache['time']) {
                ws.send(JSON.stringify({ type: 'time', data: client.cache['time'] }));
                return;
              }
              await fetchAndSendUpdate(ws, e, client, docker);
            }),
            client.subscriptions.has('list-players') ? fetchAndSendUpdate(ws, 'list-players', client, docker) : null
          ].filter(Boolean));

          client.intervals.push(setInterval(async () => {
            try {
              for (const endpoint of dynamicEndpoints) {
                if (client.subscriptions.has(endpoint) && !(endpoint === 'hello' && client.cache['hello'] || endpoint === 'time' && client.cache['time'])) {
                  await fetchAndSendUpdate(ws, endpoint, client, docker);
                }
              }
            } catch (error) {
              console.error('Error in dynamic endpoints interval:', error.message);
            }
          }, parseInt(process.env.DYNAMIC_ENDPOINTS_INTERVAL_MS, 10)));

          client.intervals.push(setInterval(async () => {
            try {
              for (const endpoint of staticEndpoints) {
                if (client.subscriptions.has(endpoint) && endpoint !== 'holesail-hashes' && endpoint !== 'internal-sftp') {
                  await fetchAndSendUpdate(ws, endpoint, client, docker);
                }
              }
            } catch (error) {
              console.error('Error in static endpoints interval:', error.message);
            }
          }, parseInt(process.env.STATIC_ENDPOINTS_INTERVAL_MS, 10)));

          // Add 10-minute interval for internal-sftp updates
          if (client.subscriptions.has('internal-sftp')) {
            const sftpIntervalId = setInterval(async () => {
              try {
                if (ws.readyState !== ws.OPEN) {
                  console.warn(`WebSocket not open (state: ${ws.readyState}) for ${user}, clearing internal-sftp interval ${sftpIntervalId}`);
                  clearInterval(sftpIntervalId);
                  client.intervals = client.intervals.filter(id => id !== sftpIntervalId);
                  return;
                }
                await fetchAndSendUpdate(ws, 'internal-sftp', client, docker);
              } catch (error) {
                console.error(`Error in internal-sftp interval for ${user}:`, error.message);
                if (ws.readyState === ws.OPEN) {
                  ws.send(JSON.stringify({ type: 'internal-sftp', error: `Failed to fetch internal-sftp data: ${error.message}` }));
                }
              }
            }, 10 * 60 * 1000); // 10 minutes
            client.intervals.push(sftpIntervalId);
            console.log(`Internal SFTP interval ID ${sftpIntervalId} added for ${user}`);
          }

          if (client.subscriptions.has('list-players') && user !== 'Unknown') {
            try {
              const container = docker.getContainer(user);
              const inspect = await container.inspect();
              if (inspect.State.Status === 'running') {
                console.log(`Starting list-players interval for ${user}`);
                client.intervals.push(setInterval(() => fetchAndSendUpdate(ws, 'list-players', client, docker), parseInt(process.env.LIST_PLAYERS_INTERVAL_MS, 10)));
              } else {
                console.log(`Container ${user} is not running, skipping list-players interval`);
                ws.send(JSON.stringify({ type: 'list-players', error: `Container ${user} is not running` }));
              }
            } catch (error) {
              console.error(`Error checking container status for list-players for ${user}:`, error.message);
              ws.send(JSON.stringify({ type: 'list-players', error: `Failed to check container status: ${error.message}` }));
            }
          }
        } else {
          console.error('Invalid /hello response:', hello);
          ws.send(JSON.stringify({ type: 'hello', error: 'Invalid hello response' }));
        }
      } else if (data.type === 'updateUser') {
        // Debounce updateUser to prevent rapid successive calls
        const now = Date.now();
        if (now - client.lastUpdateUserTime < 1000) {
          console.log(`Debouncing updateUser for ${data.user}, last update: ${client.lastUpdateUserTime}`);
          return;
        }
        client.lastUpdateUserTime = now;

        client.user = data.user;
        console.log(`Updated user to: ${client.user}`);
        if (client.user !== 'Unknown') {
          // Clear only specific intervals, preserve others
          ['connectionStatusInterval', 'geyserStatusInterval', 'sftpStatusInterval', 'statusCheckMonitorInterval'].forEach((key) => {
            if (client[key]) {
              console.log(`Clearing ${key} for ${client.user}`);
              clearInterval(client[key]);
              client[key] = null;
              client.intervals = client.intervals.filter(id => id !== client[key]);
            }
          });

          // Start Docker stats interval for new user
          startDockerStatsInterval(ws, client, client.user, docker);

          if (client.subscriptions.has('list-players')) {
            try {
              const container = docker.getContainer(client.user);
              const inspect = await container.inspect();
              if (inspect.State.Status === 'running') {
                console.log(`Starting list-players interval for new user ${client.user}`);
                client.intervals.push(setInterval(() => fetchAndSendUpdate(ws, 'list-players', client, docker), parseInt(process.env.LIST_PLAYERS_NEW_USER_INTERVAL_MS, 10)));
              } else {
                console.log(`Container ${client.user} is not running, skipping list-players interval`);
                ws.send(JSON.stringify({ type: 'list-players', error: `Container ${client.user} is not running` }));
              }
            } catch (error) {
              console.error(`Error checking container status for list-players for ${client.user}:`, error.message);
              ws.send(JSON.stringify({ type: 'list-players', error: `Failed to check container status: ${error.message}` }));
            }
          }

          await manageStatusChecks(ws, client, client.user, docker);

          if (client.subscriptions.has('docker-logs')) {
            if (client.logStream) {
              client.logStream.destroy();
              client.logStream = null;
            }
            console.log(`Starting docker logs stream for new user ${client.user}`);
            await streamContainerLogs(docker, ws, client.user, client);
          }

          // Refresh internal-sftp data for new user
          if (client.subscriptions.has('internal-sftp')) {
            try {
              await fetchAndSendUpdate(ws, 'internal-sftp', client, docker);
            } catch (error) {
              console.error(`Error refreshing internal-sftp data for new user ${client.user}:`, error.message);
              if (ws.readyState === ws.OPEN) {
                ws.send(JSON.stringify({ type: 'internal-sftp', error: `Failed to fetch internal-sftp data: ${error.message}` }));
              }
            }
          }
        }
      } else if (data.type === 'request') {
        const { requestId, endpoint, method, body } = data;
        let response;
        if (endpoint.startsWith('/docker') || endpoint === '/docker') {
          response = client.user === 'Unknown' ? { error: 'User not identified' } : await getContainerStats(docker, client.user);
          console.log(`Docker stats request response for ${client.user}:`, response);
        } else if (endpoint === '/search' && method === 'POST' && body) {
          response = await apiRequest(endpoint, client.apiKey, method, body);
          response.totalResults = response.totalResults || (response.results ? response.results.length : 0);
        } else if (endpoint === '/server-properties' && method === 'GET') {
          response = client.user === 'Unknown' ? { error: 'User not identified' } : await readServerProperties(docker, client.user);
        } else if (endpoint === '/server-properties' && method === 'POST' && body && body.content) {
          response = client.user === 'Unknown' ? { error: 'User not identified' } : await writeServerProperties(docker, client.user, body.content);
        } else if (endpoint === '/update-mods' && method === 'POST') {
          response = client.user === 'Unknown' ? { error: 'User not identified' } : await updateMods(docker, client.user);
        } else if (endpoint === '/backup' && method === 'POST') {
          response = client.user === 'Unknown' ? { error: 'User not identified' } : await createBackup(docker, client.user);
        } else {
          response = await apiRequest(endpoint, client.apiKey, method, body);
          console.log(`API request response for ${endpoint}:`, response);
        }
        if (ws.readyState === ws.OPEN) {
          ws.send(JSON.stringify({ requestId, ...response }));
        }
        if (['my-link', 'my-geyser-link', 'my-sftp'].includes(endpoint) && !response.error) {
          await fetchAndSendUpdate(ws, endpoint, client, docker);
          if (endpoint === 'my-link') {
            const linkData = await apiRequest('/my-link-cache', client.apiKey);
            if (!linkData.error) {
              client.cache['my-link-cache'] = linkData;
              try {
                const container = docker.getContainer(client.user);
                const inspect = await container.inspect();
                if (inspect.State.Status === 'running') {
                  console.log(`Performing status check after my-link request for ${client.user}`);
                  const status = await checkConnectionStatus(linkData.hostname, linkData.port);
                  ws.send(JSON.stringify({ type: 'connection-status', data: { isOnline: status.isOnline } }));
                } else {
                  ws.send(JSON.stringify({ type: 'connection-status', error: `Container ${client.user} is not running` }));
                }
              } catch (error) {
                console.error(`Error checking container status for ${client.user}:`, error.message);
                ws.send(JSON.stringify({ type: 'connection-status', error: `Failed to check container status: ${error.message}` }));
              }
            }
          } else if (endpoint === 'my-geyser-link') {
            const geyserData = await apiRequest('/my-geyser-cache', client.apiKey);
            if (!geyserData.error) {
              client.cache['my-geyser-cache'] = geyserData;
              try {
                const container = docker.getContainer(client.user);
                const inspect = await container.inspect();
                if (inspect.State.Status === 'running') {
                  console.log(`Performing status check after my-geyser-link request for ${client.user}`);
                  const status = await checkGeyserStatus(geyserData.hostname, geyserData.port);
                  ws.send(JSON.stringify({ type: 'geyser-status', data: { isOnline: status.isOnline } }));
                } else {
                  ws.send(JSON.stringify({ type: 'geyser-status', error: `Container ${client.user} is not running` }));
                }
              } catch (error) {
                console.error(`Error checking container status for ${client.user}:`, error.message);
                ws.send(JSON.stringify({ type: 'geyser-status', error: `Failed to check container status: ${error.message}` }));
              }
            }
          } else if (endpoint === 'my-sftp') {
            const sftpData = await apiRequest('/my-sftp-cache', client.apiKey);
            if (!sftpData.error) {
              client.cache['my-sftp-cache'] = sftpData;
              try {
                const container = docker.getContainer(client.user);
                const inspect = await container.inspect();
                if (inspect.State.Status === 'running') {
                  console.log(`Performing status check after my-sftp request for ${client.user}`);
                  const status = await checkSftpStatus(sftpData.hostname, sftpData.port);
                  ws.send(JSON.stringify({ type: 'sftp-status', data: { isOnline: status.isOnline } }));
                } else {
                  ws.send(JSON.stringify({ type: 'sftp-status', error: `Container ${client.user} is not running` }));
                }
              } catch (error) {
                console.error(`Error checking container status for ${client.user}:`, error.message);
                ws.send(JSON.stringify({ type: 'sftp-status', error: `Failed to check container status: ${error.message}` }));
              }
            }
          }
        }
      } else if (['kick-player', 'ban-player', 'op-player', 'deop-player'].includes(data.type)) {
        const { requestId, player } = data;
        if (!player) {
          ws.send(JSON.stringify({ requestId, error: 'Player name is required' }));
          return;
        }
        if (client.user === 'Unknown') {
          ws.send(JSON.stringify({ requestId, error: 'User not identified' }));
          return;
        }
        try {
          const container = docker.getContainer(client.user);
          const inspect = await container.inspect();
          if (inspect.State.Status !== 'running') {
            ws.send(JSON.stringify({ requestId, error: `Container ${client.user} is not running` }));
            return;
          }
          const command = {
            'kick-player': `kick ${player}`,
            'ban-player': `ban ${player}`,
            'op-player': `op ${player}`,
            'deop-player': `deop ${player}`
          }[data.type];
          const response = await apiRequest('/console', client.apiKey, 'POST', { command });
          if (!response.error) {
            const playerListResponse = await apiRequest('/list-players', client.apiKey);
            if (!playerListResponse.error) {
              ws.send(JSON.stringify({ type: 'list-players', data: playerListResponse }));
            }
          }
          if (ws.readyState === ws.OPEN) {
            ws.send(JSON.stringify({ requestId, ...response }));
          }
        } catch (error) {
          console.error(`Error processing ${data.type} for ${player}:`, error.message);
          ws.send(JSON.stringify({ requestId, error: `Failed to process command: ${error.message}` }));
        }
      } else if (data.type === 'tell-player') {
        const { requestId, player, message } = data;
        if (!player || !message) {
          ws.send(JSON.stringify({ requestId, error: 'Player name and message are required' }));
          return;
        }
        if (client.user === 'Unknown') {
          ws.send(JSON.stringify({ requestId, error: 'User not identified' }));
          return;
        }
        try {
          const container = docker.getContainer(client.user);
          const inspect = await container.inspect();
          if (inspect.State.Status !== 'running') {
            ws.send(JSON.stringify({ requestId, error: `Container ${client.user} is not running` }));
            return;
          }
          const response = await apiRequest('/tell', client.apiKey, 'POST', { username: player, message });
          if (ws.readyState === ws.OPEN) {
            ws.send(JSON.stringify({ requestId, ...response }));
          }
        } catch (error) {
          console.error(`Error sending message to ${player}:`, error.message);
          ws.send(JSON.stringify({ requestId, error: `Failed to send message: ${error.message}` }));
        }
      } else if (data.type === 'give-player') {
        const { requestId, player, item, amount } = data;
        if (!player || !item || !amount) {
          ws.send(JSON.stringify({ requestId, error: 'Player name, item, and amount are required' }));
          return;
        }
        if (client.user === 'Unknown') {
          ws.send(JSON.stringify({ requestId, error: 'User not identified' }));
          return;
        }
        try {
          const container = docker.getContainer(client.user);
          const inspect = await container.inspect();
          if (inspect.State.Status !== 'running') {
            ws.send(JSON.stringify({ requestId, error: `Container ${client.user} is not running` }));
            return;
          }
          const response = await apiRequest('/give', client.apiKey, 'POST', { username: player, item, amount });
          if (ws.readyState === ws.OPEN) {
            ws.send(JSON.stringify({ requestId, ...response }));
          }
        } catch (error) {
          console.error(`Error giving item to ${player}:`, error.message);
          ws.send(JSON.stringify({ requestId, error: `Failed to give item: ${error.message}` }));
        }
      } else if (data.type === 'refresh') {
        console.log('Processing refresh request');
        delete client.cache['hello'];
        delete client.cache['time'];
        delete client.cache['internal-sftp'];
        await Promise.all([
          ...staticEndpoints.filter(e => client.subscriptions.has(e)).map(e => fetchAndSendUpdate(ws, e, client, docker)),
          ...dynamicEndpoints.filter(e => client.subscriptions.has(e)).map(e => fetchAndSendUpdate(ws, e, client, docker)),
          client.subscriptions.has('list-players') ? fetchAndSendUpdate(ws, 'list-players', client, docker) : null
        ].filter(Boolean));
        if (client.user && client.user !== 'Unknown') {
          try {
            const stats = await getContainerStats(docker, client.user);
            console.log(`Sending refreshed docker stats for ${client.user}:`, stats);
            if (ws.readyState === ws.OPEN) {
              ws.send(JSON.stringify({ type: 'docker', data: { ...stats, user: client.user } }));
            }
            const container = docker.getContainer(client.user);
            const inspect = await container.inspect();
            if (inspect.State.Status === 'running') {
              const linkData = client.cache['my-link-cache'];
              if (linkData && linkData.hostname && linkData.port && client.subscriptions.has('my-link-cache')) {
                console.log(`Performing refresh connection status check for ${client.user}`);
                const status = await checkConnectionStatus(linkData.hostname, linkData.port);
                ws.send(JSON.stringify({ type: 'connection-status', data: { isOnline: status.isOnline } }));
              }
              const geyserData = client.cache['my-geyser-cache'];
              if (geyserData && geyserData.hostname && geyserData.port && client.subscriptions.has('my-geyser-cache')) {
                console.log(`Performing refresh Geyser status check for ${client.user}`);
                const status = await checkGeyserStatus(geyserData.hostname, geyserData.port);
                ws.send(JSON.stringify({ type: 'geyser-status', data: { isOnline: status.isOnline } }));
              }
              const sftpData = client.cache['my-sftp-cache'];
              if (sftpData && sftpData.hostname && sftpData.port && client.subscriptions.has('my-sftp-cache')) {
                console.log(`Performing refresh SFTP status check for ${client.user}`);
                const status = await checkSftpStatus(sftpData.hostname, sftpData.port);
                ws.send(JSON.stringify({ type: 'sftp-status', data: { isOnline: status.isOnline } }));
              }
            } else {
              if (client.subscriptions.has('my-link-cache')) {
                ws.send(JSON.stringify({ type: 'connection-status', error: `Container ${client.user} is not running` }));
              }
              if (client.subscriptions.has('my-geyser-cache')) {
                ws.send(JSON.stringify({ type: 'geyser-status', error: `Container ${client.user} is not running` }));
              }
              if (client.subscriptions.has('my-sftp-cache')) {
                ws.send(JSON.stringify({ type: 'sftp-status', error: `Container ${client.user} is not running` }));
              }
              if (client.subscriptions.has('internal-sftp')) {
                ws.send(JSON.stringify({ type: 'internal-sftp', error: `Container ${client.user} is not running` }));
              }
            }
          } catch (error) {
            console.error(`Error during refresh for ${client.user}:`, error.message);
            ws.send(JSON.stringify({ type: 'docker', error: `Failed to refresh stats: ${error.message}` }));
          }
        }
      }
    } catch (error) {
      console.error('WebSocket message error:', error.message);
      ws.send(JSON.stringify({ error: `Invalid message: ${error.message}` }));
    }
  });

  ws.on('close', () => {
    try {
      const client = clients.get(ws);
      client.intervals.forEach(intervalId => {
        console.log(`Clearing interval ID ${intervalId} for client ${client.user || 'unknown'}`);
        clearInterval(intervalId);
      });
      client.intervals = [];
      if (client.logStream) {
        client.logStream.destroy();
        client.logStream = null;
      }
      ['connectionStatusInterval', 'geyserStatusInterval', 'sftpStatusInterval', 'statusCheckMonitorInterval'].forEach((key) => {
        if (client[key]) {
          console.log(`Clearing ${key} for client ${client.user || 'unknown'}`);
          clearInterval(client[key]);
          client[key] = null;
        }
      });
      clearInterval(heartbeatInterval);
      clients.delete(ws);
      console.log(`WebSocket client disconnected for user ${client.user || 'unknown'}`);
    } catch (error) {
      console.error('Error on WebSocket close:', error.message);
    }
  });

  ws.on('error', (error) => console.error(`WebSocket error for user ${client.user || 'unknown'}:`, error.message));
}