/**
 * Pure helpers for the cookie-less page-view beacon (app/api/a/route.ts). Unit-tested.
 * We keep a path and a referrer *host* — nothing that identifies a person.
 */

export const MAX_BEACON_BYTES = 2048;

const BOT_PATTERN =
  /bot|crawl|spider|slurp|bingpreview|mediapartners|facebookexternalhit|embedly|quora link preview|outbrain|pinterest|vkshare|w3c_validator|whatsapp|telegram|discord|slack|lighthouse|pagespeed|headless|phantomjs|puppeteer|playwright|selenium|curl|wget|python|axios|node-fetch|undici|go-http-client|java\/|okhttp|httpclient|libwww|preview/i;

/** Crawlers, link unfurlers, monitoring and automation (including our own e2e runs) are not visitors. */
export function isBot(userAgent: string | null | undefined): boolean {
  if (!userAgent || userAgent.trim().length < 8) return true;
  return BOT_PATTERN.test(userAgent);
}

/** Visitor asked not to be tracked (Do Not Track or Global Privacy Control). */
export function prefersNoTracking(headers: Pick<Headers, 'get'>): boolean {
  return headers.get('dnt') === '1' || headers.get('sec-gpc') === '1';
}

/** Keep only a clean same-site pathname: no query string or fragment (they can carry personal data). */
export function sanitizePath(value: unknown): string | null {
  if (typeof value !== 'string') return null;
  const path = value.split(/[?#]/, 1)[0] ?? '';
  if (!path.startsWith('/') || path.startsWith('//') || path.length > 256) return null;
  if (!/^\/[A-Za-z0-9\-._~/%]*$/.test(path)) return null;
  return path;
}

/** Reduce a referrer URL to its host; drop internal, non-web and malformed referrers. */
export function referrerHost(value: unknown, ownHost: string): string | null {
  if (typeof value !== 'string' || value.length === 0 || value.length > 2048) return null;
  let url: URL;
  try {
    url = new URL(value);
  } catch {
    return null;
  }
  if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;
  const host = url.hostname.toLowerCase().replace(/^www\./, '');
  if (!host || host.length > 253) return null;
  if (host === ownHost.toLowerCase().replace(/^www\./, '')) return null;
  return host;
}

export interface PageView {
  path: string;
  referrer: string | null;
}

/** Parse the beacon body `{"p": "/path", "r": "https://referrer"}`. Null when unusable. */
export function parseBeacon(body: string, ownHost: string): PageView | null {
  if (body.length === 0 || body.length > MAX_BEACON_BYTES) return null;
  let data: unknown;
  try {
    data = JSON.parse(body);
  } catch {
    return null;
  }
  if (typeof data !== 'object' || data === null) return null;
  const record = data as Record<string, unknown>;
  const path = sanitizePath(record.p);
  if (!path) return null;
  return { path, referrer: referrerHost(record.r, ownHost) };
}
