(() => {
  const root = typeof globalThis !== "undefined" ? globalThis : self;
  const SENSITIVE_KEY_RE = /authorization|cookie|token|password|passwd|secret|credential|csrf|xsrf|ticket|signature|access[_-]?key|private[_-]?key|(^|[_-])session(?:$|[_-](?:id|key|token)(?:$|[_-]))|(^|[_-])sign(?:ed|ature)?($|[_-])/i;
  const STATIC_PATH_RE = /\.(?:js|css|mjs|map|png|jpe?g|gif|webp|svg|ico|woff2?|ttf)(?:$|\?)/i;
  const API_PATH_RE = /\/(?:api|ajax|rpc|gateway|gw|openapi|graphql|goods?|product|category|attribute|sku|shop|store|template|freight|upload|publish|create|save|submit|batch|move|task|order)(?:\/|$)|\/v\d+\//i;

  function unique(values, limit = 120) {
    return Array.from(new Set((values || []).filter(Boolean))).slice(0, limit);
  }

  function redactText(value, limit = 180) {
    return String(value ?? "")
      .replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]")
      .replace(/([?&](?:authorization|cookie|token|password|passwd|secret|credential|csrf|xsrf|ticket|signature|access[_-]?key|private[_-]?key)=)[^&#\s]+/gi, "$1[REDACTED]")
      .replace(/(["'](?:authorization|cookie|token|password|passwd|secret|credential|csrf|xsrf|ticket|signature|access[_-]?key|private[_-]?key)["']\s*:\s*["'])[^"']*/gi, "$1[REDACTED]")
      .replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[EMAIL]")
      .replace(/(?<!\d)1[3-9]\d{9}(?!\d)/g, "[PHONE]")
      .replace(/\s+/g, " ")
      .trim()
      .slice(0, Math.max(0, Number(limit) || 180));
  }

  function isSensitiveKey(value) {
    const normalized = String(value || "")
      .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
      .replace(/[^a-z0-9_-]+/gi, "_")
      .toLowerCase();
    return SENSITIVE_KEY_RE.test(normalized);
  }

  function sanitizeData(value, options = {}) {
    const maxDepth = Math.max(1, Number(options.maxDepth) || 6);
    const maxKeys = Math.max(1, Number(options.maxKeys) || 120);
    const maxArray = Math.max(1, Number(options.maxArray) || 50);
    const maxString = Math.max(16, Number(options.maxString) || 600);
    const maxNodes = Math.max(20, Number(options.maxNodes) || 500);
    const maxChars = Math.max(1000, Number(options.maxChars) || 24000);
    const seen = new WeakSet();
    let visitedNodes = 0;
    let capturedChars = 0;

    function visit(current, key = "", depth = 0) {
      if (isSensitiveKey(key)) return "[REDACTED]";
      visitedNodes += 1;
      if (visitedNodes > maxNodes) return "[TRUNCATED]";
      if (current == null || typeof current === "boolean" || typeof current === "number") return current;
      if (typeof current === "bigint") return String(current);
      if (typeof current === "string") {
        const remaining = Math.max(0, maxChars - capturedChars);
        if (!remaining) return "[TRUNCATED]";
        const result = redactText(current, Math.min(maxString, remaining));
        capturedChars += result.length;
        return result;
      }
      if (depth >= maxDepth) return Array.isArray(current) ? `[ARRAY:${current.length}]` : "[OBJECT]";
      if (typeof current !== "object") return redactText(String(current), maxString);
      if (seen.has(current)) return "[CIRCULAR]";
      seen.add(current);
      if (Array.isArray(current)) return current.slice(0, maxArray).map((item) => visit(item, "", depth + 1));
      const result = {};
      for (const childKey of Object.keys(current).slice(0, maxKeys)) {
        result[redactText(childKey, 100)] = visit(current[childKey], childKey, depth + 1);
      }
      return result;
    }

    return visit(value);
  }

  function pathTemplate(pathname) {
    return String(pathname || "/")
      .replace(/[0-9a-f]{8}-[0-9a-f-]{27,}/gi, ":uuid")
      .replace(/(?<=\/|=)\d{7,}(?=\/|$)/g, ":id")
      .slice(0, 420);
  }

  function sanitizeUrl(value, base = "https://invalid.local/") {
    try {
      const url = new URL(String(value || ""), base);
      const queryKeys = unique(
        Array.from(url.searchParams.keys()).filter((key) => !isSensitiveKey(key)),
        80
      );
      return {
        scheme: url.protocol.replace(":", ""),
        host: url.host,
        path: pathTemplate(url.pathname),
        queryKeys
      };
    } catch (_) {
      return { scheme: "", host: "", path: redactText(value, 220), queryKeys: [] };
    }
  }

  function collectFieldPaths(value, options = {}) {
    const maxDepth = Math.max(1, Number(options.maxDepth) || 5);
    const maxFields = Math.max(1, Number(options.maxFields) || 160);
    const fields = [];
    const seen = new WeakSet();

    function add(path) {
      if (!path || isSensitiveKey(path.split(".").pop()) || fields.includes(path) || fields.length >= maxFields) return;
      fields.push(path);
    }

    function visit(current, prefix = "", depth = 0) {
      if (current == null || depth > maxDepth || fields.length >= maxFields) return;
      if (typeof current !== "object") return;
      if (seen.has(current)) return;
      seen.add(current);
      if (Array.isArray(current)) {
        add(prefix ? `${prefix}[]` : "[]");
        if (current.length) visit(current[0], prefix ? `${prefix}[]` : "[]", depth + 1);
        return;
      }
      for (const key of Object.keys(current).slice(0, maxFields)) {
        if (isSensitiveKey(key)) continue;
        const path = prefix ? `${prefix}.${key}` : key;
        add(path);
        visit(current[key], path, depth + 1);
      }
    }

    visit(value);
    return fields;
  }

  function fieldsFromText(value) {
    const text = String(value || "").trim().slice(0, 100000);
    if (!text) return [];
    try {
      if (text.startsWith("{") || text.startsWith("[")) return collectFieldPaths(JSON.parse(text));
    } catch (_) {}
    try {
      return unique(Array.from(new URLSearchParams(text).keys()).filter((key) => !isSensitiveKey(key)));
    } catch (_) {
      return [];
    }
  }

  function requestBodyFields(requestBody) {
    const fields = [];
    if (!requestBody || typeof requestBody !== "object") return fields;
    if (requestBody.formData && typeof requestBody.formData === "object") {
      fields.push(...Object.keys(requestBody.formData).filter((key) => !isSensitiveKey(key)));
    }
    const rawParts = Array.isArray(requestBody.raw) ? requestBody.raw : [];
    for (const item of rawParts.slice(0, 4)) {
      const bytes = item?.bytes;
      if (!bytes) continue;
      try {
        const view = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : new Uint8Array(bytes.buffer || bytes);
        fields.push(...fieldsFromText(new TextDecoder().decode(view.slice(0, 100000))));
      } catch (_) {}
    }
    return unique(fields);
  }

  function summarizeValue(value) {
    if (value == null) return { kind: value === null ? "null" : "undefined", fields: [] };
    if (Array.isArray(value)) {
      return { kind: "array", length: value.length, fields: collectFieldPaths(value), sample: sanitizeData(value) };
    }
    if (typeof value === "object") {
      return { kind: "object", fields: collectFieldPaths(value), sample: sanitizeData(value) };
    }
    if (typeof value === "string") {
      let parsed = value;
      try {
        const text = value.trim();
        if (text.startsWith("{") || text.startsWith("[")) parsed = JSON.parse(text);
      } catch (_) {}
      return { kind: "string", length: value.length, fields: fieldsFromText(value), sample: sanitizeData(parsed) };
    }
    return { kind: typeof value, fields: [], sample: sanitizeData(value) };
  }

  function requestBodySample(requestBody) {
    if (!requestBody || typeof requestBody !== "object") return null;
    if (requestBody.formData && typeof requestBody.formData === "object") {
      return sanitizeData(requestBody.formData, { maxDepth: 4, maxArray: 30, maxString: 500 });
    }
    const rawParts = Array.isArray(requestBody.raw) ? requestBody.raw : [];
    const textParts = [];
    for (const item of rawParts.slice(0, 4)) {
      const bytes = item?.bytes;
      if (!bytes) continue;
      try {
        const view = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : new Uint8Array(bytes.buffer || bytes);
        textParts.push(new TextDecoder().decode(view.slice(0, 100000)));
      } catch (_) {}
    }
    const text = textParts.join("").trim();
    if (!text) return null;
    try { return sanitizeData(JSON.parse(text)); } catch (_) {}
    try {
      const values = {};
      for (const [key, item] of new URLSearchParams(text)) values[key] = item;
      if (Object.keys(values).length) return sanitizeData(values);
    } catch (_) {}
    return sanitizeData(text, { maxString: 1000 });
  }

  function isRelevantNetwork(details) {
    if (!details || !/^https?:/i.test(String(details.url || ""))) return false;
    const method = String(details.method || "GET").toUpperCase();
    const type = String(details.type || "").toLowerCase();
    let pathname = "";
    try {
      pathname = new URL(details.url).pathname;
    } catch (_) {}
    if (method !== "GET" && method !== "HEAD") return true;
    if (type === "xmlhttprequest" || type === "websocket") return true;
    if (STATIC_PATH_RE.test(pathname)) return false;
    return API_PATH_RE.test(pathname);
  }

  function buildSummary(events) {
    const categories = {};
    const names = {};
    const networkHosts = new Set();
    const pageHosts = new Set();
    const runtimeActions = new Set();
    for (const event of events || []) {
      categories[event.category] = (categories[event.category] || 0) + 1;
      names[event.name] = (names[event.name] || 0) + 1;
      if (event.category === "network" && event.data?.url?.host) networkHosts.add(event.data.url.host);
      if ((event.category === "navigation" || event.category === "tab") && event.data?.url?.host) pageHosts.add(event.data.url.host);
      if (event.category === "runtime" && event.data?.action) runtimeActions.add(event.data.action);
    }
    return {
      eventCount: (events || []).length,
      categories,
      topEvents: Object.entries(names).sort((a, b) => b[1] - a[1]).slice(0, 40),
      networkHosts: Array.from(networkHosts).sort(),
      pageHosts: Array.from(pageHosts).sort(),
      runtimeActions: Array.from(runtimeActions).sort()
    };
  }

  const api = {
    API_PATH_RE,
    SENSITIVE_KEY_RE,
    buildSummary,
    collectFieldPaths,
    fieldsFromText,
    isRelevantNetwork,
    isSensitiveKey,
    redactText,
    requestBodyFields,
    requestBodySample,
    sanitizeData,
    sanitizeUrl,
    summarizeValue,
    unique
  };

  root.MMWEcommerceFlowRecorderCore = api;
  if (typeof module !== "undefined" && module.exports) module.exports = api;
})();
