// packages/core-shared/src/instrumentation/otel/pii-fields.ts

// Substring match on event keys (case-insensitive).
// IP address attribute KEYS from OTel HttpInstrumentation (semconv 1.20 and 1.27+)
// are listed here so they are key-redacted in addition to the value-level regex
// scrubbing in pii-scrub-processor.ts.
export const PII_KEY_SUBSTRINGS = [
  "email",
  "password",
  "token",
  "cookie",
  "authorization",
  "set-cookie",
  "x-api-key",
  "apikey",
  "api_key",
  "secret",
  "ipaddress",
  // OTel HTTP semantic conventions — IP / client address attributes
  "client.address",
  "client_ip",
  "client.ip",
  "net.peer.ip",
  "net.sock.peer.addr",
  "net.peer.addr",
  "http.client_ip",
  "server.address",
  "host.ip",
] as const;

// Substring match on URL query-param keys (case-insensitive)
export const PII_QUERY_PARAM_SUBSTRINGS = [
  "token",
  "email",
  "password",
  "key",
  "sig",
  "signature",
  "access_token",
  "accesstoken",
  "secret",
] as const;

export const REDACTED_VALUE = "[redacted]" as const;
export const REDACTED_IP = "[redacted-ip]" as const;

// IPv4: simple dotted-quad.
export const IPV4_REGEX = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g;

// IPv6: covers the three common forms:
//   1. Full / no-:: form:       2001:0db8:0000:0000:0000:0000:0000:0001
//   2. Compressed prefix::rest: 2001:0db8::1  (one or more groups before ::)
//   3. Leading ::suffix:        ::1  or  ::ffff:192.0.2.1
// The alternation order puts the longer prefix:: pattern first so it captures
// the full address rather than leaving the prefix unmatched.
export const IPV6_REGEX =
  /\b(?:[0-9a-fA-F]{1,4}:){1,7}:[0-9a-fA-F]{0,4}\b|\b(?:[0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}\b|::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{0,4}/g;

export function keyContainsPii(key: string): boolean {
  const lower = key.toLowerCase();
  return PII_KEY_SUBSTRINGS.some((s) => lower.includes(s));
}

export function queryParamContainsPii(key: string): boolean {
  const lower = key.toLowerCase();
  return PII_QUERY_PARAM_SUBSTRINGS.some((s) => lower.includes(s));
}
