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

// AS Relationships endpoint: /api/relationships?asn=X
// Returns upstream providers, downstream customers, and peers with resolved
// names. Based on RIPE Stat asn-neighbours.
async function handleRelationships(req, res, url) {
    const rawAsn = (url.searchParams.get("asn") || "").replace(/[^0-9]/g, "");
    if (!rawAsn) {
      res.writeHead(400);
      return res.end(JSON.stringify({ error: "Missing or invalid ASN parameter" }));
    }
    const cacheKey = "relationships:" + rawAsn;
    const cached = cacheGet(cacheKey);
    if (cached) {
      res.writeHead(200, { "Content-Type": "application/json", "X-Cache": "HIT" });
      return res.end(JSON.stringify(cached));
    }
    const start = Date.now();
    try {
      const neighbourData = await fetchRipeStatCached(
        "https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + rawAsn + "&lod=1",
        { timeout: 8000 }
      );
      const neighbours = (neighbourData && neighbourData.data && neighbourData.data.neighbours) || [];
      const counts = (neighbourData && neighbourData.data && neighbourData.data.neighbour_counts) || {};

      const upstreams = neighbours.filter(n => n.type === "left").sort((a,b) => (b.power||0)-(a.power||0));
      const downstreams = neighbours.filter(n => n.type === "right").sort((a,b) => (b.power||0)-(a.power||0));
      const peers = neighbours.filter(n => n.type === "uncertain").sort((a,b) => (b.power||0)-(a.power||0));

      // Resolve AS names for top entries (upstreams + downstreams all, top 20 peers)
      const toResolve = [...upstreams, ...downstreams, ...peers.slice(0, 20)];
      const resolvedNames = {};
      await Promise.race([
        Promise.all(toResolve.map(n =>
          fetchRipeStatCached("https://stat.ripe.net/data/as-overview/data.json?resource=AS" + n.asn, { timeout: 3000 })
            .then(r => { if (r && r.data && r.data.holder) resolvedNames[n.asn] = r.data.holder; })
            .catch(() => {})
        )),
        new Promise(r => setTimeout(r, 5000)),
      ]);

      // ---- Threat Intelligence Enrichment ----
      // Enrich neighbors with threat status from local threat_intel table
      const threatMap = {};
      const allNeighborsForThreat = [...upstreams, ...downstreams, ...peers];
      const threatPromises = allNeighborsForThreat.slice(0, 100).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,
            };
          }
        } catch (e) {
          console.error(`[Relationships Threat Lookup] Error checking ASN ${n.asn}:`, e.message);
        }
      });
      await Promise.race([
        Promise.all(threatPromises),
        new Promise(r => setTimeout(r, 3000)),
      ]);

      const fmt = n => ({
        asn: n.asn,
        name: resolvedNames[n.asn] || "",
        power: n.power || 0,
        v4_peers: n.v4_peers || 0,
        v6_peers: n.v6_peers || 0,
        threat_level: threatMap[n.asn]?.threat_level || null,
        threat_confidence: threatMap[n.asn]?.confidence_score || null,
        threat_source: threatMap[n.asn]?.source || null,
      });

      const result = {
        asn: parseInt(rawAsn),
        query_time: new Date().toISOString(),
        duration_ms: Date.now() - start,
        counts: {
          upstreams: counts.left || upstreams.length,
          downstreams: counts.right || downstreams.length,
          peers_total: counts.unique || peers.length,
          uncertain: counts.uncertain || peers.length,
        },
        upstreams: upstreams.map(fmt),
        downstreams: downstreams.map(fmt),
        peers: peers.slice(0, 50).map(fmt),
        methodology: "RIPE Stat asn-neighbours API. left=upstream providers (carry your traffic), right=downstream customers (you carry their traffic), uncertain=lateral peers. Sorted by power score (number of prefixes seen via this relationship).",
        source_url: "https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + rawAsn,
      };

      // A neighbourData fetch failure (not a genuine zero-neighbour ASN) would
      // otherwise get cached as "0 upstreams/downstreams/peers" for the full 10min --
      // match the existing /api/validate precedent (90s TTL for suspicious zero counts).
      cacheSet(cacheKey, result, neighbourData ? 10 * 60 * 1000 : 90 * 1000);
      res.writeHead(200, { "Content-Type": "application/json" });
      return res.end(JSON.stringify(result, null, 2));
    } catch (err) {
      res.writeHead(500);
      return res.end(JSON.stringify({ error: "Relationships lookup failed", message: err.message }));
    }

}

module.exports = { handleRelationships };
