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

// Feature 25: Topology / AS-Relationships
async function fetchTopology(targetAsn, depth) {
  const maxDepth = Math.min(depth || 2, 3);
  const nodes = new Map();
  const edges = [];
  async function fetchNeighboursForAsn(asn, currentDepth) {
    if (nodes.has(asn) && nodes.get(asn).depth <= currentDepth) return;
    const [data, overview] = await Promise.all([
      fetchRipeStatCached("https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + asn),
      fetchRipeStatCached("https://stat.ripe.net/data/as-overview/data.json?resource=AS" + asn),
    ]);
    const name = overview?.data?.holder || "";
    const neighbours = data?.data?.neighbours || [];
    const upstreams = neighbours.filter((n) => n.type === "left");
    const downstreams = neighbours.filter((n) => n.type === "right");
    const peers = neighbours.filter((n) => n.type === "uncertain" || n.type === "peer");
    const nodeType = asn === targetAsn ? "target" : currentDepth === 1 ? "direct" : "indirect";
    nodes.set(asn, { asn, name, type: nodeType, depth: currentDepth });
    upstreams.forEach((n) => {
      if (!nodes.has(n.asn)) nodes.set(n.asn, { asn: n.asn, name: n.as_name || "", type: "upstream", depth: currentDepth + 1 });
      edges.push({ from: n.asn, to: asn, relationship: "provider-to-customer" });
    });
    downstreams.forEach((n) => {
      if (!nodes.has(n.asn)) nodes.set(n.asn, { asn: n.asn, name: n.as_name || "", type: "downstream", depth: currentDepth + 1 });
      edges.push({ from: asn, to: n.asn, relationship: "provider-to-customer" });
    });
    peers.slice(0, 10).forEach((n) => {
      if (!nodes.has(n.asn)) nodes.set(n.asn, { asn: n.asn, name: n.as_name || "", type: "peer", depth: currentDepth + 1 });
      edges.push({ from: asn, to: n.asn, relationship: "peer" });
    });
    if (currentDepth < maxDepth && upstreams.length > 0) {
      const top5 = upstreams.sort((a, b) => (b.power || 0) - (a.power || 0)).slice(0, 5);
      await Promise.all(top5.map((u) => fetchNeighboursForAsn(u.asn, currentDepth + 1)));
    }
  }
  await fetchNeighboursForAsn(targetAsn, 0);
  const edgeSet = new Set();
  const uniqueEdges = edges.filter((e) => {
    const key = e.from + "-" + e.to + "-" + e.relationship;
    if (edgeSet.has(key)) return false;
    edgeSet.add(key);
    return true;
  });
  return { nodes: [...nodes.values()], edges: uniqueEdges, target_asn: targetAsn, depth: maxDepth };
}

module.exports = { fetchTopology };
