// 11. Bogon Detection (local check, no external API calls)
function checkBogonPrefix(prefix) {
  var bogonV4 = [
    { net: "0.0.0.0", mask: 8 }, { net: "10.0.0.0", mask: 8 },
    { net: "100.64.0.0", mask: 10 }, { net: "127.0.0.0", mask: 8 },
    { net: "169.254.0.0", mask: 16 }, { net: "172.16.0.0", mask: 12 },
    { net: "192.0.2.0", mask: 24 }, { net: "192.168.0.0", mask: 16 },
    { net: "198.51.100.0", mask: 24 }, { net: "203.0.113.0", mask: 24 },
    { net: "240.0.0.0", mask: 4 },
  ];
  if (prefix.includes(":")) return { prefix: prefix, is_bogon: false, reason: "IPv6 bogon check skipped" };
  var split = prefix.split("/");
  var addr = split[0];
  var mask = parseInt(split[1] || "0");
  var parts = addr.split(".").map(Number);
  var ip = ((parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) >>> 0;
  for (var bi = 0; bi < bogonV4.length; bi++) {
    var b = bogonV4[bi];
    var bParts = b.net.split(".").map(Number);
    var bIp = ((bParts[0] << 24) | (bParts[1] << 16) | (bParts[2] << 8) | bParts[3]) >>> 0;
    var bMask = (~((1 << (32 - b.mask)) - 1)) >>> 0;
    if ((ip & bMask) === (bIp & bMask) && mask >= b.mask) {
      return { prefix: prefix, is_bogon: true, reason: "Matches bogon " + b.net + "/" + b.mask };
    }
  }
  return { prefix: prefix, is_bogon: false };
}

function checkBogonAsn(asnNum) {
  if (asnNum === 0 || asnNum === 23456 || asnNum === 65535) return true;
  if (asnNum >= 64496 && asnNum <= 64511) return true;
  if (asnNum >= 64512 && asnNum <= 65534) return true;
  return false;
}

// "pass" must mean prefixes/neighbours were actually fetched and checked clean --
// not that the upstream source failed and left nothing to check. A source is
// unavailable if it's falsy (fetchRipeStatCached network failure) OR if it's a
// truthy object with status:"error" (local-db-client.js's DB-error signal --
// see the 2026-07-16 audit; that object is NOT null, so a plain `!x` check
// alone misses this case and would show "pass" on 0 checked prefixes).
function isSourceUnavailable(x) { return !x || x.status === "error"; }

function computeBogonResult(allPrefixes, neighbours, prefixData, neighbourData) {
  var bogonPrefixResults = allPrefixes.map(checkBogonPrefix);
  var bogonPrefixes = bogonPrefixResults.filter(function(r) { return r.is_bogon; });
  var asnInPaths = neighbours.map(function(n) { return n.asn; });
  var bogonAsns = asnInPaths.filter(checkBogonAsn);
  var prefixesUnavailable = isSourceUnavailable(prefixData);
  var neighboursUnavailable = isSourceUnavailable(neighbourData);
  var bogonDataUnavailable = prefixesUnavailable && neighboursUnavailable;
  return {
    status: bogonDataUnavailable ? "info" : (bogonPrefixes.length === 0 && bogonAsns.length === 0 ? "pass" : "fail"),
    bogon_prefixes: bogonPrefixes,
    bogon_asns_in_paths: bogonAsns,
    total_prefixes_checked: allPrefixes.length,
    prefixes_source_unavailable: prefixesUnavailable,
    neighbours_source_unavailable: neighboursUnavailable,
  };
}

module.exports = { computeBogonResult };
