import { Router } from 'express';
import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { authenticateToken, optionalAuth, requireRole } from '../middleware/auth.js';
import { getServerStatus, startServer, stopServer, restartServer, getConsoleLog, getProcessUptime, listFactorioSaves, createFactorioWorld, deleteFactorioSave, getFactorioCurrentSave, isHostFailed, listZomboidConfigs, readZomboidConfig, writeZomboidConfig, listPalworldConfigs, readPalworldConfig, writePalworldConfig } from '../services/ssh.js';
import { sendRconCommand, getPlayers, getPlayerList } from '../services/rcon.js';
import { getServerMetricsHistory, getCurrentMetrics } from '../services/prometheus.js';
import { initWhitelistCache, getCachedWhitelist, setCachedWhitelist, initFactorioTemplates, getFactorioTemplates, createFactorioTemplate, deleteFactorioTemplate, initFactorioWorldSettings, getFactorioWorldSettings, saveFactorioWorldSettings, deleteFactorioWorldSettings, initAutoShutdownSettings, getAutoShutdownSettings, setAutoShutdownSettings, initActivityLog, logActivity, getActivityLog, initServerDisplaySettings, getServerDisplaySettings, getAllServerDisplaySettings, setServerDisplaySettings, initGuildSettings } from '../db/init.js';
import { getEmptySince } from '../services/autoshutdown.js';
import { getDefaultMapGenSettings, getPresetNames, getPreset } from '../services/factorio.js';

const __dirname = dirname(fileURLToPath(import.meta.url));

function loadConfig() {
  return JSON.parse(readFileSync(join(__dirname, '..', 'config.json'), 'utf-8'));
}
// RAM Budget Checkasync function checkRamBudget(serverToStart) {  const config = loadConfig();  const ramBudget = config.ramBudget || 30;  let usedRam = 0;  for (const server of config.servers) {    if (server.id === serverToStart.id) continue;    try {      const status = await getServerStatus(server);      if (status === "online") usedRam += server.maxRam || 0;    } catch (err) {}  }  const serverRam = serverToStart.maxRam || 0;  const availableRam = ramBudget - usedRam;  return { canStart: availableRam >= serverRam, usedRam, serverRam, availableRam, ramBudget };}

// Initialize tables
initWhitelistCache();
initActivityLog();
initFactorioTemplates();
initFactorioWorldSettings();
initServerDisplaySettings();
initGuildSettings();

const router = Router();

function formatBytes(bytes, forceUnit = null) {
  if (bytes === 0) return { value: 0, unit: forceUnit || "B" };
  const gb = bytes / (1024 * 1024 * 1024);
  const mb = bytes / (1024 * 1024);
  if (forceUnit === "GB") return { value: gb, unit: "GB" };
  if (forceUnit === "MB") return { value: mb, unit: "MB" };
  if (gb >= 1) return { value: gb, unit: "GB" };
  return { value: mb, unit: "MB" };
}

// ============ FACTORIO ROUTES ============

// Factorio: List saves
router.get("/factorio/saves", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "factorio");
    if (!server) return res.status(404).json({ error: "Factorio server not configured" });

    const saves = await listFactorioSaves(server);
    res.json({ saves });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Get presets and default settings
router.get("/factorio/presets", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const presets = getPresetNames();
    const defaultSettings = getDefaultMapGenSettings();
    res.json({ presets, defaultSettings });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Get preset by name
router.get("/factorio/presets/:name", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const preset = getPreset(req.params.name);
    res.json({ settings: preset });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: List templates
router.get("/factorio/templates", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const templates = getFactorioTemplates();
    res.json({ templates: templates.map(t => ({ ...t, settings: JSON.parse(t.settings) })) });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Create template
router.post("/factorio/templates", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const { name, settings } = req.body;
    if (!name || !settings) {
      return res.status(400).json({ error: "Name and settings required" });
    }
    const id = createFactorioTemplate(name, settings, req.user.id);
    res.json({ id, message: "Template created" });
  } catch (err) {
    if (err.message.includes("UNIQUE constraint")) {
      return res.status(400).json({ error: "Template name already exists" });
    }
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Delete template
router.delete("/factorio/templates/:id", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const result = deleteFactorioTemplate(parseInt(req.params.id));
    if (result.changes === 0) {
      return res.status(404).json({ error: "Template not found" });
    }
    res.json({ message: "Template deleted" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Create new world
router.post("/factorio/create-world", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const { saveName, settings } = req.body;
    if (!saveName) {
      return res.status(400).json({ error: "Save name required" });
    }

    const config = loadConfig();
    const server = config.servers.find(s => s.type === "factorio");
    if (!server) return res.status(404).json({ error: "Factorio server not configured" });

    const finalSettings = settings || getDefaultMapGenSettings();
    await createFactorioWorld(server, saveName, finalSettings);

    // Save settings to database for later reference
    saveFactorioWorldSettings(saveName, finalSettings, req.user.id);
    logActivity(req.user.id, req.user.username, 'factorio_world_create', 'factorio', saveName, req.user.discordId, req.user.avatar);

    res.json({ message: "World created", saveName });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Delete save
router.delete("/factorio/saves/:name", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "factorio");
    if (!server) return res.status(404).json({ error: "Factorio server not configured" });

    await deleteFactorioSave(server, req.params.name);
    // Also delete stored settings if they exist
    deleteFactorioWorldSettings(req.params.name);
    logActivity(req.user.id, req.user.username, 'factorio_world_delete', 'factorio', req.params.name, req.user.discordId, req.user.avatar);
    res.json({ message: "Save deleted" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Get world settings
router.get("/factorio/saves/:name/settings", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const settings = getFactorioWorldSettings(req.params.name);
    if (!settings) {
      return res.json({
        legacy: true,
        message: "This is a legacy world created before settings tracking was implemented"
      });
    }
    res.json({
      legacy: false,
      settings: JSON.parse(settings.settings),
      createdBy: settings.created_by,
      createdAt: settings.created_at
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Factorio: Get current/default save
router.get("/factorio/current-save", authenticateToken, async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "factorio");
    if (!server) return res.status(404).json({ error: "Factorio server not configured" });

    const result = await getFactorioCurrentSave(server);
    res.json(result);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// ============ ZOMBOID CONFIG ROUTES ============

// Zomboid: List config files
router.get("/zomboid/config", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "zomboid");
    if (!server) return res.status(404).json({ error: "Zomboid server not configured" });

    const files = await listZomboidConfigs(server);
    res.json({ files });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Zomboid: Read config file
router.get("/zomboid/config/:filename", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "zomboid");
    if (!server) return res.status(404).json({ error: "Zomboid server not configured" });

    const content = await readZomboidConfig(server, req.params.filename);
    res.json({ filename: req.params.filename, content });
  } catch (err) {
    if (err.message === "File not allowed") {
      return res.status(403).json({ error: err.message });
    }
    res.status(500).json({ error: err.message });
  }
});

// Zomboid: Write config file
router.put("/zomboid/config/:filename", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "zomboid");
    if (!server) return res.status(404).json({ error: "Zomboid server not configured" });

    const { content } = req.body;
    if (content === undefined) {
      return res.status(400).json({ error: "Content required" });
    }

    await writeZomboidConfig(server, req.params.filename, content);
    logActivity(req.user.id, req.user.username, 'zomboid_config', 'zomboid', req.params.filename, req.user.discordId, req.user.avatar);
    res.json({ message: "Config saved", filename: req.params.filename });
  } catch (err) {
    if (err.message === "File not allowed") {
      return res.status(403).json({ error: err.message });
    }
    res.status(500).json({ error: err.message });
  }
});


// Palworld: List config files
router.get("/palworld/config", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "palworld");
    if (!server) return res.status(404).json({ error: "Palworld server not configured" });
    const files = await listPalworldConfigs(server);
    res.json({ files });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Palworld: Read config file
router.get("/palworld/config/:filename", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "palworld");
    if (!server) return res.status(404).json({ error: "Palworld server not configured" });
    const content = await readPalworldConfig(server, req.params.filename);
    res.json({ filename: req.params.filename, content });
  } catch (err) {
    if (err.message === "File not allowed") {
      return res.status(403).json({ error: err.message });
    }
    res.status(500).json({ error: err.message });
  }
});

// Palworld: Write config file
router.put("/palworld/config/:filename", authenticateToken, requireRole("moderator"), async (req, res) => {
  try {
    const config = loadConfig();
    const server = config.servers.find(s => s.type === "palworld");
    if (!server) return res.status(404).json({ error: "Palworld server not configured" });
    const { content } = req.body;
    if (content === undefined) {
      return res.status(400).json({ error: "Content required" });
    }
    await writePalworldConfig(server, req.params.filename, content);
    logActivity(req.user.id, req.user.username, "palworld_config", "palworld", req.params.filename, req.user.discordId, req.user.avatar);
    res.json({ message: "Config saved", filename: req.params.filename });
  } catch (err) {
    if (err.message === "File not allowed") {
      return res.status(403).json({ error: err.message });
    }
    res.status(500).json({ error: err.message });
  }
});

// ============ GENERAL ROUTES ============

// Get all servers with status
router.get('/', optionalAuth, async (req, res) => {
  try {
    const config = loadConfig();
    const servers = await Promise.all(config.servers.map(async (server) => {
      // Quick check if host is unreachable - skip expensive operations
      const hostUnreachable = isHostFailed(server.host, server.sshUser);
      // If host is unreachable, return immediately with minimal data
      if (hostUnreachable) {
        const metrics = await getCurrentMetrics(server.id).catch(() => ({
          cpu: 0, cpuCores: 1, memory: 0, memoryUsed: 0, memoryTotal: 0, uptime: 0
        }));
        const memTotal = formatBytes(metrics.memoryTotal);
        const memUsed = formatBytes(metrics.memoryUsed, memTotal.unit);
        return {
          id: server.id,
          name: server.name,
          type: server.type,
          status: "unreachable",
          running: false,
          metrics: {
            cpu: metrics.cpu,
            cpuCores: metrics.cpuCores,
            memory: metrics.memory,
            memoryUsed: memUsed.value,
            memoryTotal: memTotal.value,
            memoryUnit: memTotal.unit,
            uptime: 0
          },
          players: { online: 0, max: null, list: [] },
          hasRcon: !!server.rconPassword
        };
      }

      const [status, metrics, players, playerList, processUptime] = await Promise.all([
        getServerStatus(server),
        getCurrentMetrics(server.id).catch(() => ({
          cpu: 0, cpuCores: 1, memory: 0, memoryUsed: 0, memoryTotal: 0, uptime: 0
        })),
        server.rconPassword ? getPlayers(server).catch(() => ({ online: 0, max: null })) : { online: 0, max: null },
        server.rconPassword ? getPlayerList(server).catch(() => ({ players: [] })) : { players: [] },
        getProcessUptime(server).catch(() => 0)
      ]);

      const memTotal = formatBytes(metrics.memoryTotal);
      const memUsed = formatBytes(metrics.memoryUsed, memTotal.unit);

      // Get auto-shutdown info
      const shutdownSettings = getAutoShutdownSettings(server.id);
      const emptySince = getEmptySince(server.id);

      return {
        id: server.id,
        name: server.name,
        type: server.type,
        status,
        running: status === 'online',
        metrics: {
          cpu: metrics.cpu,
          cpuCores: metrics.cpuCores,
          memory: metrics.memory,
          memoryUsed: memUsed.value,
          memoryTotal: memTotal.value,
          memoryUnit: memTotal.unit,
          uptime: processUptime
        },
        players: {
          ...players,
          list: playerList.players
        },
        hasRcon: !!server.rconPassword,
        autoShutdown: {
          enabled: shutdownSettings?.enabled === 1 || false,
          timeoutMinutes: shutdownSettings?.timeout_minutes || 15,
          emptySinceMinutes: emptySince
        }
      };
    }));

    res.json(servers);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});


// Activity Log (superadmin only)
router.get('/activity-log', authenticateToken, requireRole('superadmin'), (req, res) => {
  try {
    const limit = parseInt(req.query.limit) || 100;
    const logs = getActivityLog(limit);
    res.json(logs);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Get all server display settings (for ServerCard)
router.get("/display-settings", optionalAuth, async (req, res) => {
  try {
    const settings = getAllServerDisplaySettings();
    const result = {};
    settings.forEach(s => {
      result[s.server_id] = { address: s.address, hint: s.hint };
    });
    res.json(result);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Get single server
router.get('/:id', optionalAuth, async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) {
    return res.status(404).json({ error: 'Server not found' });
  }

  try {
    const [status, metrics, players, playerList, processUptime] = await Promise.all([
      getServerStatus(server),
      getCurrentMetrics(server.id),
      server.rconPassword ? getPlayers(server) : { online: 0, max: null },
      server.rconPassword ? getPlayerList(server) : { players: [] },
      getProcessUptime(server).catch(() => 0)
    ]);

    const memTotal = formatBytes(metrics.memoryTotal);
    const memUsed = formatBytes(metrics.memoryUsed, memTotal.unit);

    res.json({
      id: server.id,
      name: server.name,
      type: server.type,
      status,
      running: status === 'online',
      metrics: {
        cpu: metrics.cpu,
        cpuCores: metrics.cpuCores,
        memory: metrics.memory,
        memoryUsed: memUsed.value,
        memoryTotal: memTotal.value,
        memoryUnit: memTotal.unit,
        uptime: processUptime
      },
      players: {
        ...players,
        list: playerList.players
      },
      hasRcon: !!server.rconPassword
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Get metrics history from Prometheus
router.get('/:id/metrics/history', optionalAuth, async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  const range = req.query.range || '1h';
  const validRanges = ['15m', '1h', '6h', '24h'];
  if (!validRanges.includes(range)) {
    return res.status(400).json({ error: 'Invalid range. Valid: 15m, 1h, 6h, 24h' });
  }

  try {
    const history = await getServerMetricsHistory(server.id, range);
    res.json(history);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Get player list
router.get('/:id/players', authenticateToken, async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  if (!server.rconPassword) {
    return res.status(400).json({ error: 'RCON not configured for this server' });
  }

  try {
    const [count, list] = await Promise.all([
      getPlayers(server),
      getPlayerList(server)
    ]);
    res.json({ ...count, list: list.players });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Get console logs (moderator+)
router.get('/:id/logs', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  try {
    const lines = parseInt(req.query.lines) || 100;
    const logs = await getConsoleLog(server, lines);
    res.json({ logs });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Power actions (moderator+)
router.post('/:id/start', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  try {
    const { save } = req.body || {};
    await startServer(server, { save });
    logActivity(req.user.id, req.user.username, 'server_start', server.id, save ? 'Save: ' + save : null, req.user.discordId, req.user.avatar);
    res.json({ message: 'Server starting' });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/:id/stop', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  try {
    await stopServer(server);
    logActivity(req.user.id, req.user.username, 'server_stop', server.id, null, req.user.discordId, req.user.avatar);
    res.json({ message: 'Server stopping' });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/:id/restart', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  try {
    await restartServer(server);
    logActivity(req.user.id, req.user.username, 'server_restart', server.id, null, req.user.discordId, req.user.avatar);
    res.json({ message: 'Server restarting' });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Get whitelist (with server-side caching)
router.get('/:id/whitelist', optionalAuth, async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  if (!server.rconPassword) {
    return res.json({ players: [], cached: false });
  }

  try {
    const response = await sendRconCommand(server, 'whitelist list');
    const match = response.trim().match(/:\s*(.+)$/);
    let players = [];
    if (match && match[1]) {
      players = match[1].split(',').map(p => p.trim()).filter(p => p.length > 0);
    }
    setCachedWhitelist(server.id, players);
    res.json({ players, cached: false });
  } catch (err) {
    const players = getCachedWhitelist(server.id);
    res.json({ players, cached: true });
  }
});

// RCON command (moderator+)
router.post('/:id/rcon', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  if (!server.rconPassword) {
    return res.status(400).json({ error: 'RCON not configured for this server' });
  }

  const { command } = req.body;
  if (!command) {
    return res.status(400).json({ error: 'Command required' });
  }

  try {
    const response = await sendRconCommand(server, command);
    logActivity(req.user.id, req.user.username, 'rcon_command', server.id, command, req.user.discordId, req.user.avatar);
    if (command.startsWith("whitelist ")) {
      try {
        const listResponse = await sendRconCommand(server, "whitelist list");
        const match = listResponse.trim().match(/:\s*(.+)$/);
        let players = [];
        if (match && match[1]) {
          players = match[1].split(",").map(p => p.trim()).filter(p => p.length > 0);
        }
        setCachedWhitelist(server.id, players);
      } catch (e) { /* ignore */ }
    }
    res.json({ response });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});


// Initialize auto-shutdown settings table
initAutoShutdownSettings();

// ============ AUTO-SHUTDOWN ROUTES ============

// Get auto-shutdown settings for a server
router.get('/:id/autoshutdown', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  const settings = getAutoShutdownSettings(req.params.id);
  const emptySince = getEmptySince(req.params.id);

  res.json({
    enabled: settings?.enabled === 1 || false,
    timeoutMinutes: settings?.timeout_minutes || 15,
    emptySinceMinutes: emptySince
  });
});

// Update auto-shutdown settings for a server
router.put('/:id/autoshutdown', authenticateToken, requireRole('moderator'), async (req, res) => {
  const config = loadConfig();
  const server = config.servers.find(s => s.id === req.params.id);
  if (!server) return res.status(404).json({ error: 'Server not found' });

  const { enabled, timeoutMinutes } = req.body;
  const timeout = Math.max(1, Math.min(1440, timeoutMinutes || 15));

  setAutoShutdownSettings(req.params.id, enabled, timeout);
  logActivity(req.user.id, req.user.username, 'autoshutdown_config', req.params.id, 'Enabled: ' + enabled + ', Timeout: ' + timeout + ' min', req.user.discordId, req.user.avatar);
  console.log('[AutoShutdown] Settings updated for ' + req.params.id + ': enabled=' + enabled + ', timeout=' + timeout + 'min');

  res.json({ message: 'Auto-shutdown settings updated', enabled, timeoutMinutes: timeout });
});


// Get display settings for a specific server
router.get("/:id/display-settings", authenticateToken, requireRole("superadmin"), async (req, res) => {
  try {
    const settings = getServerDisplaySettings(req.params.id);
    res.json(settings || { server_id: req.params.id, address: "", hint: "" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Update display settings for a server (superadmin only)
router.put("/:id/display-settings", authenticateToken, requireRole("superadmin"), async (req, res) => {
  const { address, hint } = req.body;
  try {
    setServerDisplaySettings(req.params.id, address || "", hint || "");
    res.json({ message: "Display settings updated", address, hint });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});
export default router;
