/**
 * Classify a hostname / URL host as private (local LAN / loopback) vs public.
 * Used so Gemma on 192.168.x is labeled `local`, not `cloud`.
 */

/** Strip protocol + path; return host[:port] token. */
export function hostFromUrl(urlOrHost: string): string {
  const s = urlOrHost.trim();
  const noProto = s.replace(/^https?:\/\//i, '');
  return (noProto.split('/')[0] || '').toLowerCase();
}

/** Host without port for IP / name checks. */
function hostnameOnly(host: string): string {
  if (host.startsWith('[')) {
    const end = host.indexOf(']');
    return end >= 0 ? host.slice(1, end) : host;
  }
  // IPv6 without brackets rarely appears with port in our URLs
  if (host.includes(':') && host.split(':').length === 2) {
    return host.split(':')[0];
  }
  if (/^\d+\.\d+\.\d+\.\d+:\d+$/.test(host)) return host.split(':')[0];
  return host;
}

function ipv4Octets(host: string): number[] | null {
  const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
  if (!m) return null;
  const o = [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];
  if (o.some(n => n > 255)) return null;
  return o;
}

/**
 * True for loopback, RFC1918, *.local (mDNS), and IPv6 loopback.
 * False for public cloud API hosts.
 */
export function isPrivateHost(urlOrHost: string): boolean {
  const host = hostnameOnly(hostFromUrl(urlOrHost));
  if (!host) return false;
  if (host === 'localhost' || host === '::1' || host === '0:0:0:0:0:0:0:1') return true;
  if (host.endsWith('.local')) return true;

  const o = ipv4Octets(host);
  if (o) {
    // 127.0.0.0/8
    if (o[0] === 127) return true;
    // 10.0.0.0/8
    if (o[0] === 10) return true;
    // 172.16.0.0/12
    if (o[0] === 172 && o[1] >= 16 && o[1] <= 31) return true;
    // 192.168.0.0/16
    if (o[0] === 192 && o[1] === 168) return true;
    return false;
  }

  return false;
}
