import { isIP } from "node:net";

function isPrivateIpv4(value: string) {
  const octets = value.split(".").map(Number);
  if (octets.length !== 4 || octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) return true;

  const [first, second] = octets;
  return first === 0 || first === 10 || first === 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168 || first >= 224;
}

function isPrivateIpv6(value: string) {
  const normalized = value.toLowerCase();
  return normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe80:");
}

export function isPublicNetworkAddress(address: string) {
  const version = isIP(address);
  if (version === 4) return !isPrivateIpv4(address);
  if (version === 6) return !isPrivateIpv6(address);
  return false;
}

export function normalizePublicSiteUrl(value: string) {
  const url = new URL(value.trim());
  const hostname = url.hostname.toLowerCase();

  if (url.protocol !== "https:" || url.username || url.password || url.port || hostname === "localhost" || hostname.endsWith(".local")) {
    throw new Error("Only public HTTPS sites can be validated.");
  }

  if (isIP(hostname) && !isPublicNetworkAddress(hostname)) {
    throw new Error("Only public HTTPS sites can be validated.");
  }

  url.pathname = "/";
  url.search = "";
  url.hash = "";
  return url;
}
