const localDb = require("../../local-db-client");
const { getRpkiAspaLastFetch, rpkiAspaMap } = require("../services/rpki");
const { pdbSourceCache } = require("../caches/pdb-source-cache");
const { roaStore } = require("../caches/roa-store");
const { ripeStatCache } = require("../services/ripe-stat");
const { responseCache } = require("../caches/response-caches");
const { aspaAdoptionDailyHistory } = require("../aspa-adoption/tracker");

const BGPROUTES_API_KEY = process.env.BGPROUTES_API_KEY || "";

function aspaAdoptionDelta() {
  return aspaAdoptionDailyHistory.length >= 2
    ? aspaAdoptionDailyHistory[aspaAdoptionDailyHistory.length - 1].aspa_objects - aspaAdoptionDailyHistory[aspaAdoptionDailyHistory.length - 2].aspa_objects
    : 0;
}

// Health endpoint — extended with cache status, ASPA metrics, and local DB stats
function handleHealth(req, res) {
  const mem = process.memoryUsage();
  const rpkiAspaLastFetch = getRpkiAspaLastFetch();
  const aspaAge = rpkiAspaLastFetch ? Math.floor((Date.now() - rpkiAspaLastFetch) / 60000) : -1;
  // Bug fix 2026-07-17: previously only declared inside the .then() callback
  // below, so the .catch() branch's reference to it threw ReferenceError
  // (never caught -- the response just hung until client timeout).
  const roaAge = roaStore.lastBuild ? Math.floor((Date.now() - roaStore.lastBuild) / 60000) : -1;
  const pdbTotal = pdbSourceCache.hits + pdbSourceCache.misses;

  // Query local DB stats (async, but return partial if needed)
  localDb.getLocalDbStats().then(function(dbStats) {
    // Determine health status based on local DB data availability
    const hasLocalBgp = dbStats && dbStats.bgp_routes > 100000; // should have >2M rows normally
    const hasLocalRpki = dbStats && dbStats.rpki_roas > 100000; // should have >500k rows normally
    const status = (hasLocalBgp && hasLocalRpki && aspaAge < 300) ? "ok" : "degraded";

    const healthResponse = {
      status,
      service: "PeerCortex",
      version: "0.6.9",
      timestamp: new Date().toISOString(),
      uptime_seconds: Math.floor(process.uptime()),
      memory_mb: Math.round(mem.heapUsed / 1024 / 1024),
      bgproutes_configured: !!BGPROUTES_API_KEY,
      caches: {
        aspa_map: { entries: rpkiAspaMap.size, age_minutes: aspaAge },
        pdb_net: { entries: pdbSourceCache.net.size, hit_rate_pct: pdbTotal > 0 ? Math.round(pdbSourceCache.hits / pdbTotal * 100) : 0 },
        pdb_netixlan: { entries: pdbSourceCache.netixlan.size },
        pdb_netfac: { entries: pdbSourceCache.netfac.size },
        ripe_stat: { entries: ripeStatCache.size },
        response_cache: { entries: responseCache.size },
      },
      local_db: dbStats ? {
        bgp_routes: dbStats.bgp_routes,
        rpki_roas: dbStats.rpki_roas,
        threat_intel: dbStats.threat_intel,
        rdap_cache_entries: dbStats.rdap_cache_entries,
        source: "PostgreSQL (local)",
        healthy: hasLocalBgp && hasLocalRpki,
      } : null,
      aspa_adoption: {
        total_objects: rpkiAspaMap.size,
        roa_count: roaStore.count,
        history_samples: aspaAdoptionDailyHistory.length,
        delta_last: aspaAdoptionDelta(),
      },
    };
    return res.end(JSON.stringify(healthResponse, null, 2));
  }).catch(function(e) {
    console.error('[/api/health] Local DB stats error:', e.message);
    // Return health without local DB stats on error. Local DB stats failed
    // to fetch, so "ok" can't be confirmed -- report degraded, matching the
    // honest-degradation pattern used throughout this codebase.
    const status = "degraded";
    return res.end(
      JSON.stringify({
        status,
        service: "PeerCortex",
        version: "0.6.9",
        timestamp: new Date().toISOString(),
        uptime_seconds: Math.floor(process.uptime()),
        memory_mb: Math.round(mem.heapUsed / 1024 / 1024),
        bgproutes_configured: !!BGPROUTES_API_KEY,
        caches: {
          roa_store: { entries: roaStore.count, age_minutes: roaAge, ready: roaStore.ready },
          aspa_map: { entries: rpkiAspaMap.size, age_minutes: aspaAge },
          pdb_net: { entries: pdbSourceCache.net.size, hit_rate_pct: pdbTotal > 0 ? Math.round(pdbSourceCache.hits / pdbTotal * 100) : 0 },
          pdb_netixlan: { entries: pdbSourceCache.netixlan.size },
          pdb_netfac: { entries: pdbSourceCache.netfac.size },
          ripe_stat: { entries: ripeStatCache.size },
          response_cache: { entries: responseCache.size },
        },
        local_db: { error: "Could not fetch local DB stats", message: e.message },
        aspa_adoption: {
          total_objects: rpkiAspaMap.size,
          roa_count: roaStore.count,
          history_samples: aspaAdoptionDailyHistory.length,
          delta_last: aspaAdoptionDelta(),
        },
      }, null, 2)
    );
  });
  return;
}

module.exports = { handleHealth };
