const { fetchJSON } = require("./services/http-helpers");
const { whoisCacheGet, whoisCacheSet, WHOIS_NOT_FOUND_CACHE_TTL } = require("./caches/response-caches");

// Feature 27: WHOIS via RIPE DB
async function fetchWhois(resource) {
  const result = { resource, type: null, data: null, error: null };
  try {
    const trimmed = resource.trim();
    if (/^(AS)?\d+$/i.test(trimmed)) {
      result.type = "aut-num";
      const asn = trimmed.replace(/^AS/i, "");

      // Check cache first
      const cached = whoisCacheGet(asn);
      if (cached !== undefined) {
        result.data = cached;
        if (!cached) result.error = "Not found in any RIR database (cached)";
        return result;
      }

      // Try RIPE first
      const ripeData = await fetchJSON("https://rest.db.ripe.net/search.json?query-string=AS" + asn + "&type-filter=aut-num&source=ripe", { timeout: 5000 }).catch(() => null);
      if (ripeData && ripeData.objects && ripeData.objects.object) {
        const obj = ripeData.objects.object[0];
        const attrs = obj.attributes?.attribute || [];
        const parsed = {};
        attrs.forEach((a) => { if (!parsed[a.name]) parsed[a.name] = []; parsed[a.name].push(a.value); });
        result.data = {
          aut_num: (parsed["aut-num"] || [])[0] || "",
          as_name: (parsed["as-name"] || [])[0] || "",
          descr: parsed["descr"] || [],
          org: (parsed["org"] || [])[0] || "",
          admin_c: parsed["admin-c"] || [],
          tech_c: parsed["tech-c"] || [],
          mnt_by: parsed["mnt-by"] || [],
          status: (parsed["status"] || [])[0] || "",
          created: (parsed["created"] || [])[0] || "",
          last_modified: (parsed["last-modified"] || [])[0] || "",
          source: (parsed["source"] || [])[0] || "",
          import: parsed["import"] || [],
          export: parsed["export"] || [],
          remarks: parsed["remarks"] || [],
        };
        whoisCacheSet(asn, result.data);
      }

      // If RIPE didn't find it, try all other RIRs via RDAP in parallel (3s timeout)
      if (!result.data) {
        const rdapEndpoints = [
          { name: "APNIC", url: "https://rdap.apnic.net/autnum/" + asn },
          { name: "ARIN", url: "https://rdap.arin.net/registry/autnum/" + asn },
          { name: "LACNIC", url: "https://rdap.lacnic.net/rdap/autnum/" + asn },
          { name: "AFRINIC", url: "https://rdap.afrinic.net/rdap/autnum/" + asn },
        ];
        const rdapResults = await Promise.all(rdapEndpoints.map((ep) =>
          fetchJSON(ep.url, { timeout: 3000 }).then((d) => {
            if (!d || d.errorCode || !d.handle) return null;
            return { source: ep.name, data: d };
          }).catch(() => null)
        ));
        const found = rdapResults.find((r) => r !== null);
        if (found) {
          const d = found.data;
          const remarks = (d.remarks || []).map((r) => (r.description || []).join(" "));
          const entities = d.entities || [];
          const adminContacts = entities.filter((e) => (e.roles || []).includes("administrative")).map((e) => e.handle || "");
          const techContacts = entities.filter((e) => (e.roles || []).includes("technical")).map((e) => e.handle || "");
          const events = d.events || [];
          const created = (events.find((e) => e.eventAction === "registration") || {}).eventDate || "";
          const lastMod = (events.find((e) => e.eventAction === "last changed") || {}).eventDate || "";
          result.data = {
            aut_num: "AS" + asn,
            as_name: d.name || "",
            descr: remarks,
            org: (entities.find((e) => (e.roles || []).includes("registrant")) || {}).handle || "",
            admin_c: adminContacts,
            tech_c: techContacts,
            mnt_by: [],
            status: (d.status || []).join(", "),
            created: created,
            last_modified: lastMod,
            source: found.source + " (RDAP)",
            import: [],
            export: [],
            remarks: remarks,
          };
          whoisCacheSet(asn, result.data);
        } else {
          result.error = "Not found in any RIR database (RIPE, APNIC, ARIN, LACNIC, AFRINIC)";
          // Short TTL: this "not found" likely reflects a transient failure across
          // all 5 sources, not a confirmed non-existent ASN -- see WHOIS_NOT_FOUND_CACHE_TTL.
          whoisCacheSet(asn, null, WHOIS_NOT_FOUND_CACHE_TTL);
        }
      }
    } else if (/[\/:]/.test(trimmed) || /^\d+\.\d+\.\d+/.test(trimmed)) {
      result.type = "inetnum";
      const ripeData = await fetchJSON("https://rest.db.ripe.net/search.json?query-string=" + encodeURIComponent(trimmed) + "&type-filter=inetnum,inet6num");
      if (ripeData && ripeData.objects && ripeData.objects.object) {
        const results = ripeData.objects.object.map((obj) => {
          const attrs = obj.attributes?.attribute || [];
          const parsed = {};
          attrs.forEach((a) => { if (!parsed[a.name]) parsed[a.name] = []; parsed[a.name].push(a.value); });
          return {
            inetnum: (parsed["inetnum"] || parsed["inet6num"] || [])[0] || "",
            netname: (parsed["netname"] || [])[0] || "",
            descr: parsed["descr"] || [],
            country: (parsed["country"] || [])[0] || "",
            org: (parsed["org"] || [])[0] || "",
            admin_c: parsed["admin-c"] || [],
            tech_c: parsed["tech-c"] || [],
            mnt_by: parsed["mnt-by"] || [],
            status: (parsed["status"] || [])[0] || "",
            created: (parsed["created"] || [])[0] || "",
            last_modified: (parsed["last-modified"] || [])[0] || "",
            source: (parsed["source"] || [])[0] || "",
          };
        });
        result.data = results.length === 1 ? results[0] : results;
      } else { result.error = "Not found in RIPE DB"; }
    } else {
      result.type = "domain";
      const ripeData = await fetchJSON("https://rest.db.ripe.net/search.json?query-string=" + encodeURIComponent(trimmed) + "&type-filter=domain");
      if (ripeData && ripeData.objects && ripeData.objects.object) {
        const obj = ripeData.objects.object[0];
        const attrs = obj.attributes?.attribute || [];
        const parsed = {};
        attrs.forEach((a) => { if (!parsed[a.name]) parsed[a.name] = []; parsed[a.name].push(a.value); });
        result.data = {
          domain: (parsed["domain"] || [])[0] || "",
          descr: parsed["descr"] || [],
          admin_c: parsed["admin-c"] || [],
          tech_c: parsed["tech-c"] || [],
          zone_c: parsed["zone-c"] || [],
          nserver: parsed["nserver"] || [],
          mnt_by: parsed["mnt-by"] || [],
          created: (parsed["created"] || [])[0] || "",
          last_modified: (parsed["last-modified"] || [])[0] || "",
          source: (parsed["source"] || [])[0] || "",
        };
      } else { result.error = "Not found in RIPE DB"; }
    }
  } catch (err) { result.error = err.message; }
  return result;
}

module.exports = { fetchWhois };
