<?php
// ═══════════════════════════════════════════════════════════════════════════════════════════════
// PURPOSE
//   Remote node metrics endpoint. The monitor page's partner cards — CPU, memory, storage,
//   uptime and container counts for every host other than this one.
//
// OPERATIONAL MODEL
//   Split from monitor.php on cost, not on subject. Local metrics are cheap file reads;
//   remote metrics are SSH round trips to every partner. Keeping them on separate URLs lets
//   the page poll local stats often and remote stats rarely, and lets a dark partner slow
//   only its own request. Served from a 1-hour cache by default; ?live bypasses it for the
//   page's explicit refresh button.
//
// DESIGN PRINCIPLES
//   The cache is the default and the live call is the exception.
//       An hour is deliberately long. Partner hardware stats do not move fast enough to
//       justify paying SSH latency on every page load, and the refresh button exists for the
//       moment someone actually needs current numbers.
//
//   Every payload carries its own timestamp.
//       ts is written into the cached document, so the page can render the age rather than
//       presenting hour-old numbers as current.
//
//   The live path writes the cache too.
//       A manual refresh benefits every subsequent visitor instead of being discarded.
//
// OPERATIONAL SAFEGUARDS
//   Cache miss is distinguished from empty payload.
//       vv_cache_read() returns null on a miss, expiry, or unparseable file, and the check is
//       an explicit !== null. A legitimately empty result — the single-host case, where there
//       are no remote hosts at all — is served from cache rather than being mistaken for a
//       miss and forced onto the SSH path on every single poll.
//
//   Read-only over SSH. The remote commands are stat collection only; nothing is started,
//   stopped, or written on a partner.
//
//   Unreachable partners degrade per node inside vv_remote_hosts_stats(), so one dark host
//   cannot empty the other cards.
//
//   HTTP caching is disabled even though the payload is cached server-side.
//       The two are not the same lever. The server-side cache has an age the page can see and
//       a bypass it can trigger; a browser or proxy cache has neither, and would defeat ?live
//       entirely.
//
// REQUEST
//   GET             served from the 3600s cache when one is present
//   GET ?live       bypass the cache, collect fresh, and rewrite it
//
// RESPONSE
//   {"remote_hosts":{…},"ts":epoch}
//
// DEPENDS ON
//   include/monitor.php   vv_remote_hosts_stats(), vv_cache_read(), vv_cache_write()
// ═══════════════════════════════════════════════════════════════════════════════════════════════
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store');
require_once dirname(__DIR__) . '/include/monitor.php';

if (!isset($_GET['live'])) {
    $cached = vv_cache_read('monitor_remote', 3600);
    if ($cached !== null) { echo json_encode($cached); exit; }
}

$data = ['remote_hosts' => vv_remote_hosts_stats(), 'ts' => time()];
vv_cache_write('monitor_remote', $data);
echo json_encode($data);
