import { spawn } from "node:child_process";
import { resolveAgentRuntimePaths } from "./runtime-paths.mjs";

function cleanDNSName(value) {
  return typeof value === "string" ? value.trim().replace(/\.$/, "") : "";
}

function runJson(command, args, timeoutMs = 5_000) {
  return new Promise((resolve, reject) => {
    const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
    const stdout = [];
    const stderr = [];
    const timer = setTimeout(() => child.kill("SIGTERM"), timeoutMs);
    child.stdout.on("data", (chunk) => stdout.push(chunk));
    child.stderr.on("data", (chunk) => stderr.push(chunk));
    child.once("error", (error) => {
      clearTimeout(timer);
      reject(error);
    });
    child.once("close", (code) => {
      clearTimeout(timer);
      if (code !== 0) {
        reject(new Error(Buffer.concat(stderr).toString("utf8").trim() || `${command} exited with ${code}`));
        return;
      }
      try {
        resolve(JSON.parse(Buffer.concat(stdout).toString("utf8")));
      } catch (error) {
        reject(error);
      }
    });
  });
}

export function tailscalePeerCandidates(status) {
  return Object.values(status?.Peer || {})
    .filter((peer) => peer?.Online && String(peer?.OS || "").toLowerCase() === "macos")
    .map((peer) => {
      const dnsName = cleanDNSName(peer.DNSName);
      if (!dnsName) return null;
      return {
        baseURL: `https://${dnsName}`,
        fallbackName: String(peer.HostName || "").trim() || dnsName.replace(/\.ts\.net$/i, ""),
      };
    })
    .filter(Boolean);
}

export async function discoverTailscalePeerAgents({
  status,
  fetchImpl = globalThis.fetch,
  timeoutMs = 2_500,
} = {}) {
  const tailscaleStatus = status || await runJson(resolveAgentRuntimePaths().tailscaleCLI, ["status", "--json"]);
  const candidates = tailscalePeerCandidates(tailscaleStatus);
  const results = await Promise.all(candidates.map(async (candidate) => {
    try {
      const response = await fetchImpl(`${candidate.baseURL}/api/discovery`, {
        cache: "no-store",
        signal: AbortSignal.timeout(timeoutMs),
      });
      if (!response.ok) return null;
      const payload = await response.json();
      if (payload?.product !== "private-reel" || !payload?.peerId) return null;
      return {
        peerId: String(payload.peerId),
        name: String(payload.name || candidate.fallbackName),
        baseURL: candidate.baseURL,
        capabilities: payload.capabilities && typeof payload.capabilities === "object"
          ? payload.capabilities
          : {},
      };
    } catch {
      return null;
    }
  }));
  return results.filter(Boolean);
}

export function tailscaleSelfURL(status) {
  const dnsName = cleanDNSName(status?.Self?.DNSName);
  return dnsName ? `https://${dnsName}` : "";
}
