/**
 * Modpack Installer — Trinity Console routes
 * Task #101 — REQ-2026-04-16-modpack-installer
 *
 * GET  /admin/modpack-installer                     — main installer page
 * GET  /admin/modpack-installer/search              — HTMX: search packs
 * GET  /admin/modpack-installer/pack/:provider/:id  — HTMX: pack details + versions
 * POST /admin/modpack-installer/install             — enqueue install job
 * GET  /admin/modpack-installer/status/:id          — job status page
 * GET  /admin/modpack-installer/history             — install history
 * GET  /admin/modpack-installer/pending-spawns      — Holly's spawn verification queue
 * POST /admin/modpack-installer/verify-spawn/:id    — mark spawn verified
 */

const express = require('express');
const router = express.Router();
const axios = require('axios');
const db = require('../../database');
const { getProvider, listProviders } = require('../../services/providerApi');
const { estimateRam, slugify } = require('../../services/modpackInstaller');

const PANEL_URL = process.env.PANEL_URL || 'https://panel.firefrostgaming.com';
const PANEL_ADMIN_KEY = process.env.PANEL_ADMIN_KEY || '';

// Aikar G1GC flags template — {RAM} replaced with allocation in MB
const AIKAR_FLAGS = '-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 ' +
  '-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch ' +
  '-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M ' +
  '-XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 ' +
  '-XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 ' +
  '-XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem ' +
  '-XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs ' +
  '-Daikars.new.flags=true';

function javaVersionForMC(mcVersion) {
  if (!mcVersion) return 21;
  const parts = mcVersion.split('.').map(Number);
  const minor = parts[1] || 0;
  if (minor <= 16) return 8;
  if (minor <= 20) return 17;
  return 21;
}

// ─── Node resource usage (JSON for form) ────────────────────────────────────
router.get('/node-info', async (req, res) => {
  try {
    const panelHeaders = {
      'Authorization': `Bearer ${PANEL_ADMIN_KEY}`,
      'Accept': 'application/json'
    };
    const nodesResp = await axios.get(`${PANEL_URL}/api/application/nodes`, {
      headers: panelHeaders, timeout: 10000
    });
    const nodes = (nodesResp.data.data || []).map(n => {
      const a = n.attributes;
      return {
        id: a.id, name: a.name, location_id: a.location_id,
        memory: a.memory, memory_overallocate: a.memory_overallocate,
        disk: a.disk, disk_overallocate: a.disk_overallocate,
        allocated_resources: a.allocated_resources || {}
      };
    });
    // Map to our node IDs
    const result = {};
    for (const n of nodes) {
      const key = n.name.includes('TX') ? 'TX1' : n.name.includes('NC') ? 'NC1' : n.name;
      const usedRam = n.allocated_resources.memory || 0;
      const usedDisk = n.allocated_resources.disk || 0;
      result[key] = {
        label: key === 'TX1' ? '🔥 TX1 — Dallas' : '❄️ NC1 — Charlotte',
        ramUsedMb: usedRam, ramTotalMb: n.memory,
        diskUsedMb: usedDisk, diskTotalMb: n.disk
      };
    }
    res.json(result);
  } catch (err) {
    console.error('[Installer] node-info error:', err.message);
    res.json({
      NC1: { label: '❄️ NC1 — Charlotte', ramUsedMb: 0, ramTotalMb: 65536, diskUsedMb: 0, diskTotalMb: 2048000 },
      TX1: { label: '🔥 TX1 — Dallas', ramUsedMb: 0, ramTotalMb: 65536, diskUsedMb: 0, diskTotalMb: 2048000 }
    });
  }
});

// ─── Next available port on a node ──────────────────────────────────────────
router.get('/next-port', async (req, res) => {
  try {
    const node = req.query.node || 'NC1';
    // Query server_config for all servers on this node, find max port
    const result = await db.query(
      `SELECT COALESCE(MAX(server_port), 25564) AS max_port FROM server_config WHERE node = $1`,
      [node]
    );
    const nextPort = result.rows[0].max_port + 1;
    res.json({ port: nextPort, node });
  } catch (err) {
    console.error('[Installer] next-port error:', err.message);
    res.json({ port: 25565, node: req.query.node || 'NC1' });
  }
});

// ─── Main page ──────────────────────────────────────────────────────────────
router.get('/', (req, res) => {
  res.render('admin/modpack-installer/index', {
    title: 'Modpack Installer',
    currentPath: '/modpack-installer',
    providers: listProviders(),
    adminUser: req.user,
    layout: 'layout'
  });
});

// ─── Vanilla/Paper install form (HTMX partial) ─────────────────────────────
router.get('/vanilla-form', (req, res) => {
  res.render('admin/modpack-installer/_vanilla_form', {
    aikarFlags: AIKAR_FLAGS,
    csrfToken: req.csrfToken(),
    layout: false
  });
});

// ─── Search packs (HTMX partial) ───────────────────────────────────────────
router.get('/search', async (req, res) => {
  try {
    const { provider, q, gameVersion, modLoader } = req.query;
    const api = getProvider(provider);
    if (!api) return res.send('<div class="text-red-400 text-sm">Unknown provider</div>');

    const result = await api.searchPacks(q || '', { gameVersion, modLoader });
    if (result.stub) {
      return res.send(`<div class="text-yellow-400 text-sm p-4">${result.message}</div>`);
    }

    res.render('admin/modpack-installer/_pack_list', {
      packs: result.packs,
      provider,
      layout: false
    });
  } catch (err) {
    console.error('[Installer] search error:', err.message);
    res.send(`<div class="text-red-400 text-sm p-4">Search failed: ${err.message}</div>`);
  }
});

// ─── Pack details + versions (HTMX partial) ────────────────────────────────
router.get('/pack/:provider/:id', async (req, res) => {
  try {
    const api = getProvider(req.params.provider);
    if (!api) return res.send('<div class="text-red-400">Unknown provider</div>');

    const [details, versions] = await Promise.all([
      api.getPackDetails(req.params.id),
      api.listVersions(req.params.id)
    ]);

    res.render('admin/modpack-installer/_pack_details', {
      pack: details,
      versions,
      provider: req.params.provider,
      estimateRam,
      slugify,
      javaVersionForMC,
      aikarFlags: AIKAR_FLAGS,
      csrfToken: req.csrfToken(),
      layout: false
    });
  } catch (err) {
    console.error('[Installer] pack details error:', err.message);
    res.send(`<div class="text-red-400 text-sm p-4">Failed to load pack: ${err.message}</div>`);
  }
});

// ─── Enqueue install job ────────────────────────────────────────────────────
router.post('/install', async (req, res) => {
  try {
    const { provider, packId, versionId, shortName, displayName, node, ramMb,
            diskMb, spawnType, javaVersion, port, jvmArgs } = req.body;

    if (!shortName || !displayName || !node) {
      return res.status(400).send('Missing required fields');
    }

    // For vanilla: provider=paper, packId=paper, versionId=MC version
    const isVanilla = spawnType === 'vanilla';
    if (!isVanilla && (!provider || !packId || !versionId)) {
      return res.status(400).send('Missing modpack fields');
    }

    // Validate short_name
    if (!/^[a-z0-9-]+$/.test(shortName)) {
      return res.status(400).send('Short name must be lowercase letters, numbers, and hyphens only');
    }

    // Check for duplicate short_name
    const dup = await db.query('SELECT 1 FROM server_config WHERE short_name = $1', [shortName]);
    if (dup.rows.length > 0) {
      return res.status(400).send(`Short name "${shortName}" already in use`);
    }

    const installId = require('crypto').randomUUID();
    const triggeredBy = req.user?.username || 'Trinity Console';

    // Create install_history record
    await db.query(`
      INSERT INTO install_history (id, job_type, target_version_id, triggered_by, status)
      VALUES ($1, 'fresh_install', $2, $3, 'queued')
    `, [installId, versionId, triggeredBy]);

    // Enqueue pg-boss job
    const boss = req.app.locals.pgBoss;
    if (!boss) {
      await db.query(`UPDATE install_history SET status = 'failed', error_message = 'pg-boss not initialized' WHERE id = $1`, [installId]);
      return res.status(500).send('Job queue not available — pg-boss failed to initialize');
    }

    // Extract server.properties overrides (fields prefixed sp_)
    const serverProperties = {};
    for (const [key, val] of Object.entries(req.body)) {
      if (key.startsWith('sp_') && val !== undefined && val !== '') {
        serverProperties[key.slice(3).replace(/_/g, '-')] = val;
      }
    }

    await boss.send('modpack-installs', {
      installId,
      provider: isVanilla ? 'paper' : provider,
      packId: isVanilla ? 'paper' : packId,
      versionId: isVanilla ? versionId : versionId,
      mcVersion: isVanilla ? versionId : null,
      shortName, displayName, node,
      ramMb: parseInt(ramMb) || 8192,
      diskMb: parseInt(diskMb) || 20480,
      spawnType: spawnType || 'vanilla',
      javaVersion: parseInt(javaVersion) || null,
      port: parseInt(port) || null,
      serverProperties: Object.keys(serverProperties).length > 0 ? serverProperties : null,
      triggeredBy
    });

    res.redirect(`/admin/modpack-installer/status/${installId}`);
  } catch (err) {
    console.error('[Installer] enqueue error:', err);
    res.status(500).send(`Install failed: ${err.message}`);
  }
});

// ─── Job status page ────────────────────────────────────────────────────────
router.get('/status/:id', async (req, res) => {
  try {
    const result = await db.query('SELECT * FROM install_history WHERE id = $1', [req.params.id]);
    if (result.rows.length === 0) return res.status(404).send('Job not found');

    res.render('admin/modpack-installer/status', {
      title: 'Install Status',
      currentPath: '/modpack-installer',
      job: result.rows[0],
      adminUser: req.user,
      layout: 'layout'
    });
  } catch (err) {
    console.error('[Installer] status error:', err);
    res.status(500).send('Error loading status');
  }
});

// ─── Job status API (for polling from status page) ──────────────────────────
router.get('/status/:id/json', async (req, res) => {
  try {
    const result = await db.query('SELECT * FROM install_history WHERE id = $1', [req.params.id]);
    if (result.rows.length === 0) return res.status(404).json({ error: 'Not found' });
    res.json(result.rows[0]);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// ─── Install history ────────────────────────────────────────────────────────
router.get('/history', async (req, res) => {
  try {
    const { status } = req.query;
    let where = '';
    const params = [];
    if (status) { where = 'WHERE status = $1'; params.push(status); }

    const result = await db.query(
      `SELECT h.*, sc.display_name as server_name
       FROM install_history h
       LEFT JOIN server_config sc ON sc.server_identifier = h.server_identifier
       ${where} ORDER BY h.started_at DESC LIMIT 50`,
      params
    );

    res.render('admin/modpack-installer/history', {
      title: 'Install History',
      currentPath: '/modpack-installer',
      jobs: result.rows,
      filters: { status },
      adminUser: req.user,
      layout: 'layout'
    });
  } catch (err) {
    console.error('[Installer] history error:', err);
    res.status(500).send('Error loading history');
  }
});

// ─── Pending spawns (Holly's queue) ─────────────────────────────────────────
router.get('/pending-spawns', async (req, res) => {
  try {
    const result = await db.query(
      `SELECT * FROM server_config
       WHERE spawn_verified = false AND modpack_provider IS NOT NULL
       ORDER BY created_at DESC`
    );

    res.render('admin/modpack-installer/pending-spawns', {
      title: 'Pending Spawn Verification',
      currentPath: '/modpack-installer',
      servers: result.rows,
      adminUser: req.user,
      layout: 'layout'
    });
  } catch (err) {
    console.error('[Installer] pending-spawns error:', err);
    res.status(500).send('Error loading pending spawns');
  }
});

// ─── Mark spawn verified ────────────────────────────────────────────────────
router.post('/verify-spawn/:identifier', async (req, res) => {
  try {
    await db.query(
      `UPDATE server_config SET spawn_verified = true, updated_at = NOW()
       WHERE server_identifier = $1`,
      [req.params.identifier]
    );
    res.redirect('/admin/modpack-installer/pending-spawns');
  } catch (err) {
    console.error('[Installer] verify-spawn error:', err);
    res.status(500).send('Error');
  }
});

module.exports = router;
