const localDb = require("../../../local-db-client");
const { fetchRipeStatCached } = require("../../services/ripe-stat");

// Resolve empty AS names — all in parallel, with 3s timeout. Mutates entries
// in place (matches original control flow).
async function resolveEmptyNames(neighbourLists) {
  const emptyNameNeighbours = neighbourLists.flat().filter(n => !n.name);
  if (emptyNameNeighbours.length === 0) return;
  const resolvePromise = Promise.all(
    emptyNameNeighbours.map(n =>
      fetchRipeStatCached("https://stat.ripe.net/data/as-overview/data.json?resource=AS" + n.asn, { timeout: 3000 })
        .then(r => { if (r?.data?.holder) n.name = r.data.holder; })
        .catch(() => {})
    )
  );
  await Promise.race([resolvePromise, new Promise(r => setTimeout(r, 3000))]);
}

// Threat Intelligence Enrichment for Neighbors: enrich neighbor data with
// threat status from the local threat_intel table. Batch lookups (cap at 50
// to avoid overwhelming DB), 4s timeout.
async function buildThreatMap(neighbors) {
  const threatMap = {};
  const toCheck = neighbors.slice(0, 50);
  const threatPromises = toCheck.map(async (n) => {
    try {
      const asNum = String(n.asn);
      const threat = await localDb.getThreatIntel(asNum);
      if (threat) {
        threatMap[n.asn] = {
          threat_level: threat.threat_level,
          confidence_score: threat.confidence_score,
          source: threat.source,
          cached_at: threat.cached_at,
        };
      }
    } catch (e) {
      // Gracefully skip on error
      console.error(`[Threat Lookup] Error checking ASN ${n.asn}:`, e.message);
    }
  });

  await Promise.race([
    Promise.all(threatPromises),
    new Promise(r => setTimeout(r, 4000)),
  ]);

  return threatMap;
}

function attachThreat(n, threatMap) {
  return {
    ...n,
    threat_level: threatMap[n.asn]?.threat_level || null,
    threat_confidence: threatMap[n.asn]?.confidence_score || null,
    threat_source: threatMap[n.asn]?.source || null,
  };
}

// Full enrichment pipeline: resolve empty names, then attach threat intel to
// upstreams/downstreams/peers. Returns new arrays (does not mutate the input
// arrays themselves, though resolveEmptyNames does mutate entry.name).
async function enrichNeighbours(upstreams, downstreams, peers) {
  await resolveEmptyNames([upstreams, downstreams, peers]);
  const threatMap = await buildThreatMap([...upstreams, ...downstreams, ...peers]);
  return {
    upstreams: upstreams.map(n => attachThreat(n, threatMap)),
    downstreams: downstreams.map(n => attachThreat(n, threatMap)),
    peers: peers.map(n => attachThreat(n, threatMap)),
  };
}

module.exports = { enrichNeighbours };
