import { lookup } from "node:dns/promises";
import { isIP } from "node:net";
import { randomUUID } from "node:crypto";
import { isPublicNetworkAddress, normalizePublicSiteUrl } from "./url";

export type AgentValidation = {
  siteId: string;
  pluginVersion?: string;
  capabilitiesUrl?: string;
  normalizedUrl: string;
};

type AgentPayload = {
  success?: boolean;
  site_id?: string;
  version?: string;
  capabilities_url?: string;
};

export async function assertPublicDnsTarget(hostname: string) {
  if (isIP(hostname)) return;

  const addresses = await lookup(hostname, { all: true, verbatim: true });
  if (!addresses.length || addresses.some(({ address }) => !isPublicNetworkAddress(address))) {
    throw new Error("The site URL must resolve only to a public address.");
  }
}

export async function validateSiteAgent(urlValue: string, token: string): Promise<AgentValidation> {
  const siteUrl = normalizePublicSiteUrl(urlValue);
  await assertPublicDnsTarget(siteUrl.hostname);

  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), 12_000);
  try {
    const endpoint = new URL("/wp-json/site-agent/v1/agent", siteUrl.origin);
    const response = await fetch(endpoint, {
      method: "GET",
      headers: {
        "X-Site-Agent-Token": token,
        "X-Site-Agent-Timestamp": String(Math.floor(Date.now() / 1000)),
        "X-Site-Agent-Nonce": randomUUID(),
        Accept: "application/json",
      },
      cache: "no-store",
      redirect: "error",
      signal: controller.signal,
    });
    const payload: unknown = await response.json().catch(() => null);
    if (!response.ok || !payload || typeof payload !== "object") {
      throw new Error("The plugin did not accept this token or remote access is disabled.");
    }

    const data = payload as AgentPayload;
    if (!data.success || !data.site_id) {
      throw new Error("The plugin could not confirm this site. Check remote access and token permissions.");
    }

    return {
      siteId: data.site_id,
      pluginVersion: data.version,
      capabilitiesUrl: data.capabilities_url,
      normalizedUrl: siteUrl.origin,
    };
  } catch (error) {
    if (error instanceof Error && error.name === "AbortError") {
      throw new Error("The site did not respond in time. Confirm the public URL and try again.");
    }
    throw error;
  } finally {
    clearTimeout(timeout);
  }
}
