import { isBlockedHostnameOrIp } from "openclaw/plugin-sdk/infra-runtime";

export type UrbitBaseUrlValidation =
  | { ok: true; baseUrl: string; hostname: string }
  | { ok: false; error: string };

function hasScheme(value: string): boolean {
  return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
}

export function validateUrbitBaseUrl(raw: string): UrbitBaseUrlValidation {
  const trimmed = String(raw ?? "").trim();
  if (!trimmed) {
    return { ok: false, error: "Required" };
  }

  const candidate = hasScheme(trimmed) ? trimmed : `https://${trimmed}`;

  let parsed: URL;
  try {
    parsed = new URL(candidate);
  } catch {
    return { ok: false, error: "Invalid URL" };
  }

  if (!["http:", "https:"].includes(parsed.protocol)) {
    return { ok: false, error: "URL must use http:// or https://" };
  }

  if (parsed.username || parsed.password) {
    return { ok: false, error: "URL must not include credentials" };
  }

  const hostname = parsed.hostname.trim().toLowerCase().replace(/\.$/, "");
  if (!hostname) {
    return { ok: false, error: "Invalid hostname" };
  }

  // Normalize to origin so callers can't smuggle paths/query fragments into the base URL,
  // and strip a trailing dot from the hostname (DNS root label).
  const isIpv6 = hostname.includes(":");
  const host = parsed.port
    ? `${isIpv6 ? `[${hostname}]` : hostname}:${parsed.port}`
    : isIpv6
      ? `[${hostname}]`
      : hostname;

  return { ok: true, baseUrl: `${parsed.protocol}//${host}`, hostname };
}

export function isBlockedUrbitHostname(hostname: string): boolean {
  const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
  if (!normalized) {
    return false;
  }
  return isBlockedHostnameOrIp(normalized);
}
