/**
 * routes/health.js — Public health probes; no auth, no rate limit.
 *
 * Owns: GET /api/health (liveness + DB latency + queue counters),
 *       GET /api/agent/health (build SHA + minimum supported agent version).
 * Does NOT own: authentication, agent long-poll, or any business logic.
 *
 * Mounted BEFORE the generalApiLimiter in server.js so health probes are
 * never throttled — agent installs and Render health checks must always pass.
 */

const express = require('express');
const fs = require('fs');
const path = require('path');
const { execFileSync } = require('child_process');
const router = express.Router();
const pool = require('../db/index');

// The root VERSION file is the ONE source of truth (see CLAUDE.md "Versioning").
// Do NOT fall back to package.json: it drifted to 1.0.0 while the shipped release
// was 1.2.2, and every self-hosted install then reported a wrong version. 'unknown'
// is strictly better than confidently wrong.
const PKG_VERSION = (() => {
  try {
    return fs.readFileSync(path.join(__dirname, '..', 'VERSION'), 'utf8').trim() || 'unknown';
  } catch { return 'unknown'; }
})();

// Build SHA — resolved once at module load.
//
// This used to read RENDER_GIT_COMMIT, which has been dead since the OCI cutover
// (deploy is now a git-pull cron on the VM, not a Render build), so /api/health
// reported build_sha "unknown" and there was no way to confirm WHICH commit was
// live — the exact blind spot the marker-file deploy made matter.
//
// Order: explicit env override -> the deploy marker written by deploy/auto-deploy.sh
// on a fully successful deploy -> git HEAD. The self-hosted release zip is cut with
// `git archive` and has no .git, so it legitimately reports 'unknown' there.
const BUILD_SHA = (() => {
  const env = process.env.GIT_SHA || process.env.RENDER_GIT_COMMIT;
  if (env) return env.trim().slice(0, 40);

  const marker = process.env.TUNEVAULT_DEPLOY_MARKER
    || path.join(process.env.HOME || '', '.tunevault-last-deployed-sha');
  try {
    const sha = fs.readFileSync(marker, 'utf8').trim();
    if (/^[0-9a-f]{7,40}$/i.test(sha)) return sha;
  } catch { /* no marker (dev box, container) — fall through to git */ }

  try {
    return execFileSync('git', ['rev-parse', 'HEAD'], {
      cwd: path.join(__dirname, '..'),
      encoding: 'utf8',
      timeout: 2000,
      stdio: ['ignore', 'pipe', 'ignore'],
    }).trim();
  } catch { return 'unknown'; }
})();

// Minimum agent version that the cloud currently supports.
// Bump this when a new agent release drops compatibility with old poll protocol.
const MIN_AGENT_VERSION = '6.0.0';

const HEALTH_HEADERS = {
  'Cache-Control': 'no-store',
  'Access-Control-Allow-Origin': '*',
};

// GET /api/health — public liveness probe.
// Returns 200 { status:'ok', ... } or 503 { status:'degraded', ... } if DB unreachable.
// Called by: agent CLI on startup, Render health checker, external uptime monitors.
router.get('/health', async (req, res) => {
  res.set(HEALTH_HEADERS);

  const start = Date.now();
  let dbConnected = false;
  let dbLatencyMs = null;
  let pendingCommands = 0;
  let agentsOnline = 0;

  try {
    // Single round-trip; also fetches queue counters to save a second query.
    const queueResult = await pool.query(`
      SELECT
        (SELECT COUNT(*) FROM agent_command_results WHERE status = 'pending') AS pending_commands,
        (SELECT COUNT(*) FROM agent_tunnels WHERE last_heartbeat > CURRENT_TIMESTAMP - INTERVAL '90' SECOND) AS agents_online
      FROM DUAL
    `);
    dbLatencyMs = Date.now() - start;
    dbConnected = true;
    pendingCommands = parseInt(queueResult.rows[0].pending_commands, 10);
    agentsOnline = parseInt(queueResult.rows[0].agents_online, 10);
  } catch {
    dbLatencyMs = Date.now() - start;
  }

  res.status(dbConnected ? 200 : 503).json({
    status: dbConnected ? 'ok' : 'degraded',
    version: PKG_VERSION,
    build_sha: BUILD_SHA,
    uptime_seconds: Math.floor(process.uptime()),
    timestamp: new Date().toISOString(),
    db: { connected: dbConnected, latency_ms: dbLatencyMs },
    queue: { pending_commands: pendingCommands, agents_online: agentsOnline },
    region: process.env.RENDER_REGION || 'unknown',
  });
});

// GET /api/agent/health — extended probe for agent self-upgrade gate.
// Returns build SHA + minimum supported agent version so agents can decide
// whether they need to upgrade before connecting.
// Called by: agent CLI upgrade-check path.
router.get('/agent/health', (req, res) => {
  res.set(HEALTH_HEADERS);
  res.json({
    status: 'ok',
    version: PKG_VERSION,
    build_sha: BUILD_SHA,
    min_agent_version: MIN_AGENT_VERSION,
    timestamp: new Date().toISOString(),
  });
});

module.exports = router;
