import { Rcon } from 'rcon-client';

const rconConnections = new Map();
const playerCache = new Map();
const CACHE_TTL = 30000; // 30 seconds

// Palworld REST API helper
async function getPalworldPlayers(server) {
  const port = server.restApiPort || 8212;
  const url = `http://${server.host}:${port}/v1/api/players`;
  const auth = Buffer.from(`admin:${server.rconPassword}`).toString('base64');

  const response = await fetch(url, {
    headers: { 'Authorization': `Basic ${auth}` },
    signal: AbortSignal.timeout(5000)
  });

  if (!response.ok) {
    throw new Error(`REST API error: ${response.status}`);
  }

  return await response.json();
}

async function getConnection(server) {
  const key = `${server.host}:${server.rconPort}`;

  if (rconConnections.has(key)) {
    const conn = rconConnections.get(key);
    if (conn.authenticated) {
      return conn;
    }
    rconConnections.delete(key);
  }

  const rcon = await Rcon.connect({
    host: server.host,
    port: server.rconPort,
    password: server.rconPassword,
    timeout: 5000
  });

  rcon.on('error', (err) => {
    console.error(`RCON error for ${key}:`, err.message);
    rconConnections.delete(key);
  });

  rcon.on('end', () => {
    rconConnections.delete(key);
  });

  // Handle socket errors to prevent crash
  if (rcon.socket) {
    rcon.socket.on('error', (err) => {
      console.error(`RCON socket error for ${key}:`, err.message);
      rconConnections.delete(key);
    });
  }

  rconConnections.set(key, rcon);
  return rcon;
}

export async function sendRconCommand(server, command) {
  if (!server.rconPassword) {
    throw new Error('RCON password not configured');
  }

  const rcon = await getConnection(server);
  return await rcon.send(command);
}

export async function getPlayers(server) {
  const cacheKey = `${server.id}-count`;
  const cached = playerCache.get(cacheKey);

  if (cached && Date.now() - cached.time < CACHE_TTL) {
    return cached.data;
  }

  try {
    let result = { online: 0, max: null };

    if (server.type === 'minecraft') {
      const response = await sendRconCommand(server, 'list');
      const match = response.match(/There are (\d+) of a max of (\d+) players online/);
      if (match) {
        result = { online: parseInt(match[1]), max: parseInt(match[2]) };
      }
    } else if (server.type === 'factorio') {
      const response = await sendRconCommand(server, '/players online count');
      const match = response.match(/(\d+)/);
      if (match) {
        result = { online: parseInt(match[1]), max: null };
      }
    } else if (server.type === 'zomboid') {
      const response = await sendRconCommand(server, 'players');
      // Format: "Players connected (X):" or "Players connected (X): Player1, Player2"
      const match = response.match(/Players connected \((\d+)\)/);
      if (match) {
        result = { online: parseInt(match[1]), max: null };
      }
    } else if (server.type === 'vrising') {
      const response = await sendRconCommand(server, 'listusers');
      // Count lines that contain player info
      const lines = response.split('\n').filter(l => l.trim() && !l.includes('listusers'));
      result = { online: lines.length, max: null };
    } else if (server.type === 'palworld') {
      // Use REST API instead of RCON for Palworld
      const data = await getPalworldPlayers(server);
      result = { online: data.players?.length || 0, max: null };
    }

    playerCache.set(cacheKey, { data: result, time: Date.now() });
    return result;
  } catch (err) {
    console.error(`Failed to get players for ${server.id}:`, err.message);
    // Clear cache on error - server might be offline
    playerCache.delete(cacheKey);
    return { online: 0, max: null };
  }
}

export async function getPlayerList(server) {
  const cacheKey = `${server.id}-list`;
  const cached = playerCache.get(cacheKey);

  if (cached && Date.now() - cached.time < CACHE_TTL) {
    return cached.data;
  }

  try {
    let players = [];

    if (server.type === 'minecraft') {
      const response = await sendRconCommand(server, 'list');
      // Format: "There are X of a max of Y players online: Player1, Player2, Player3"
      const colonIndex = response.indexOf(':');
      if (colonIndex !== -1) {
        const playerPart = response.substring(colonIndex + 1).trim();
        if (playerPart) {
          players = playerPart.split(',').map(p => p.trim()).filter(p => p);
        }
      }
    } else if (server.type === 'factorio') {
      const response = await sendRconCommand(server, '/players online');
      // Format: "Online players (X):\n  player1 (online)\n  player2 (online)"
      const lines = response.split('\n');
      for (const line of lines) {
        const match = line.match(/^\s*(\S+)\s*\(online\)/);
        if (match) {
          players.push(match[1]);
        }
      }
    } else if (server.type === 'zomboid') {
      const response = await sendRconCommand(server, 'players');
      // Format: "Players connected (X): \n-Player1\n-Player2\n-Player3"
      const lines = response.split('\n');
      for (const line of lines) {
        const trimmed = line.trim();
        if (trimmed.startsWith('-')) {
          players.push(trimmed.substring(1));
        }
      }
    } else if (server.type === 'vrising') {
      const response = await sendRconCommand(server, 'listusers');
      // Parse player names from listusers output
      const lines = response.split('\n').filter(l => l.trim() && !l.includes('listusers'));
      players = lines.map(l => l.trim()).filter(p => p);
    } else if (server.type === 'palworld') {
      // Use REST API instead of RCON for Palworld
      const data = await getPalworldPlayers(server);
      players = (data.players || []).map(p => p.name);
    }

    const result = { players };
    playerCache.set(cacheKey, { data: result, time: Date.now() });
    return result;
  } catch (err) {
    console.error(`Failed to get player list for ${server.id}:`, err.message);
    // Clear cache on error - server might be offline
    playerCache.delete(cacheKey);
    return { players: [] };
  }
}
