/**
 * Grax compatibility shim
 *
 * MAIN-world, document_start compatibility layer. The shim is browser-injected
 * through chrome.scripting.registerContentScripts; it never appends a <script>
 * element and therefore does not rewrite or weaken the host page's CSP.
 *
 * Compatibility objects are installed only after a Grax neutral mock response
 * announces itself, or after a confirmed tracking-script/runtime failure. The
 * Claude application and security-verification frames are intentionally left
 * completely native so anti-bot integrity checks never inspect a Grax proxy.
 */
(() => {
  'use strict';

  try {
    const ROOT = globalThis;
    const NATIVE_STUB_SOURCE = 'function () { [native code] }';
    const NATIVE_APPLICATION_BYPASS = Object.freeze([
      'claude.ai',
      'anthropic.com'
    ]);
    const SECURITY_VERIFICATION_HOSTS = Object.freeze([
      'challenges.cloudflare.com',
      'hcaptcha.com',
      'recaptcha.net',
      'arkoselabs.com',
      'funcaptcha.com',
      'captcha-delivery.com',
      'datadome.co'
    ]);
    const SECURITY_REFERENCE_PATTERN = /(?:\/cdn-cgi\/(?:challenge-platform|challenge|turnstile)(?:\/|$)|\/turnstile\/v0\/|\/recaptcha\/(?:api|enterprise|releases)(?:\/|$)|__cf_chl_|cf-turnstile-response|h-captcha-response|g-recaptcha-response|funcaptcha|arkose|datadome)/i;

    function hostnameMatches(hostname, domains) {
      try {
        return Boolean(hostname && domains.some(domain =>
          hostname === domain || hostname.endsWith(`.${domain}`)
        ));
      } catch {
        return false;
      }
    }

    function safeHostname(value) {
      try { return new URL(String(value || ''), location.href).hostname.toLowerCase(); } catch { return ''; }
    }

    function isNativeBypassContext() {
      try {
        const hostname = String(location.hostname || safeHostname(location.href) || '').toLowerCase();
        if (hostnameMatches(hostname, NATIVE_APPLICATION_BYPASS)) return true;
        if (hostnameMatches(hostname, SECURITY_VERIFICATION_HOSTS)) return true;
        const combined = `${location.href || ''} ${document.referrer || ''} ${window.name || ''}`;
        return SECURITY_REFERENCE_PATTERN.test(combined);
      } catch {
        return false;
      }
    }

    if (isNativeBypassContext()) return;

    const INSTANCE_KEY = '__graxCompatibilityShimInstalledV4__';
    if (ROOT[INSTANCE_KEY]) return;

    try {
      Object.defineProperty(ROOT, INSTANCE_KEY, {
        value: true,
        configurable: true,
        enumerable: false,
        writable: false
      });
    } catch {
      try { ROOT[INSTANCE_KEY] = true; } catch {}
    }

    const STATE_EVENT = '__grax_guard_state_v1__';
    const MOCK_READY_EVENT = '__grax_telemetry_mock_ready_v1__';
    const MARK = Symbol.for('grax.telemetry.stub');
    const TRACKING_HOSTS = Object.freeze([
      'sentry.io', 'sentry-cdn.com',
      'mixpanel.com', 'mxpnl.com',
      'google-analytics.com', 'analytics.google.com', 'googletagmanager.com', 'doubleclick.net',
      'datadoghq.com', 'datadoghq-browser-agent.com',
      'segment.com', 'segment.io', 'segmentapis.com',
      'intercom.io', 'intercomcdn.com', 'intercomassets.com',
      'hubspot.com', 'hubspot.net', 'hs-analytics.net', 'hs-scripts.com', 'hscollectedforms.net',
      'newrelic.com', 'nr-data.net',
      'amplitude.com', 'hotjar.com', 'hotjar.io', 'clarity.ms',
      'fullstory.com', 'logrocket.io', 'bugsnag.com', 'bugsnagjs.com',
      'rollbar.com', 'rollbarcdn.com', 'heap.io', 'heapanalytics.com',
      'rudderstack.com', 'rudderlabs.com', 'posthog.com', 'appcues.com',
      'pendo.io', 'mouseflow.com', 'smartlook.com', 'inspectlet.com', 'crazyegg.com'
    ]);

    const TRACKING_HINT = /(?:sentry|mixpanel|google-analytics|gtag|googletagmanager|doubleclick|datadog|segment|intercom|hubspot|newrelic|amplitude|hotjar|clarity|fullstory|logrocket|bugsnag|rollbar|heapanalytics|rudderstack|posthog|appcues|pendo|mouseflow|smartlook|inspectlet|crazyegg)/i;
    const TRACKING_RUNTIME_FAILURE = /(?:is not defined|cannot read (?:properties|property) of (?:undefined|null)|is not a function|undefined is not an object|null is not an object)/i;
    const CALLBACK_METHODS = new Set([
      'withScope', 'configureScope', 'startSpan', 'startSpanManual',
      'startTransaction', 'onLoad', 'onReady', 'ready', 'addEventProcessor',
      'onFeatureFlags', 'onSessionId', 'onCapture', 'use', 'add', 'register'
    ]);
    const STRING_METHODS = new Set([
      'get_distinct_id', 'getDistinctId', 'get_session_id', 'getSessionId',
      'getAnonymousId', 'anonymousId', 'getUserId', 'getDeviceId',
      'captureException', 'captureMessage', 'captureEvent', 'getTraceId'
    ]);
    const BOOLEAN_METHODS = new Set([
      'isInitialized', 'isReady', 'isSupported', 'hasLoaded',
      'isEnabled', 'isActive', 'hasOptedOutTracking'
    ]);
    const NUMBER_METHODS = new Set([
      'getCount', 'size', 'length', 'getSessionReplayLink'
    ]);
    const ARRAY_METHODS = new Set([
      'getAll', 'entries', 'values', 'keys', 'getBreadcrumbs'
    ]);

    const GLOBAL_NAMES = Object.freeze([
      'Intercom', 'hj', 'clarity', 'FS', 'FullStory', 'plausible', 'matomo',
      'mixpanel', 'analytics', 'Sentry', 'DD_RUM', 'DD_LOGS', 'datadog',
      'datadogRum', 'datadogLogs', 'HubSpotConversations', 'amplitude',
      'LogRocket', 'newrelic', 'NREUM', 'Bugsnag', 'Rollbar', 'heap',
      'posthog', 'rudderanalytics', 'Appcues', 'pendo', 'smartlook',
      'mouseflow', 'Inspectlet', 'snowplow', 'utag', '_satellite',
      'optimizely', 'Kameleoon', 'Tealium', 'AdobeAnalytics'
    ]);

    const installed = new Map();
    const stealthFunctions = new WeakSet();
    let protectionActive = false;
    let mockObserved = false;
    let trackingFailureObserved = false;
    let functionToStringMask = null;

    const nativeAddEventListener = EventTarget.prototype.addEventListener;
    const nativeFunctionToStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, 'toString');
    const nativeFunctionToString = nativeFunctionToStringDescriptor?.value;

    function mark(value) {
      try {
        Object.defineProperty(value, MARK, {
          value: true,
          configurable: true,
          enumerable: false,
          writable: false
        });
      } catch {}
      try {
        if (typeof value === 'function') stealthFunctions.add(value);
      } catch {}
      return value;
    }

    function isStealthFunction(value) {
      try {
        return typeof value === 'function' && (stealthFunctions.has(value) || value[MARK] === true);
      } catch {
        return false;
      }
    }

    function installFunctionToStringMask() {
      try {
        if (!nativeFunctionToString || functionToStringMask) return;
        const current = Object.getOwnPropertyDescriptor(Function.prototype, 'toString');
        if (current?.value !== nativeFunctionToString) return;

        const maskedToString = function toString() {
          try {
            if (isStealthFunction(this)) return NATIVE_STUB_SOURCE;
          } catch {}
          return Reflect.apply(nativeFunctionToString, this, []);
        };
        mark(maskedToString);
        Object.defineProperty(Function.prototype, 'toString', {
          value: maskedToString,
          configurable: nativeFunctionToStringDescriptor?.configurable !== false,
          enumerable: nativeFunctionToStringDescriptor?.enumerable === true,
          writable: nativeFunctionToStringDescriptor?.writable !== false
        });
        functionToStringMask = maskedToString;
      } catch {}
    }

    function restoreFunctionToStringMask() {
      try {
        if (!functionToStringMask || !nativeFunctionToStringDescriptor) return;
        const current = Object.getOwnPropertyDescriptor(Function.prototype, 'toString');
        if (current?.value === functionToStringMask) {
          Object.defineProperty(Function.prototype, 'toString', nativeFunctionToStringDescriptor);
        }
      } catch {}
      functionToStringMask = null;
    }

    function hostMatches(hostname) {
      try {
        return Boolean(
          hostname && TRACKING_HOSTS.some(domain =>
            hostname === domain || hostname.endsWith(`.${domain}`)
          )
        );
      } catch {
        return false;
      }
    }

    function isTrackingUrl(value) {
      if (typeof value !== 'string' || !value.trim()) return false;
      try {
        const url = new URL(value, location.href);
        return hostMatches(url.hostname.toLowerCase()) || TRACKING_HINT.test(url.href);
      } catch {
        try { return TRACKING_HINT.test(value); } catch { return false; }
      }
    }

    function nativeUtility(callback) {
      return mark(function () {
        try { return Reflect.apply(callback, this, arguments); } catch { return undefined; }
      });
    }

    const nativeStringifier = nativeUtility(() => NATIVE_STUB_SOURCE);
    const emptyJson = nativeUtility(() => ({}));
    const zeroValue = nativeUtility(() => 0);
    const primitiveValue = nativeUtility(() => '');
    const emptyIterator = mark(function* () {});
    const emptyAsyncIterator = mark(async function* () {});

    function createRecursiveCallable(label, options = {}) {
      const cache = new Map();
      const queue = [];

      const make = path => {
        if (cache.has(path)) return cache.get(path);

        let proxy;
        const target = mark(function () {
          return proxy;
        });
        try {
          Object.defineProperty(target, 'name', {
            value: '',
            configurable: true,
            enumerable: false,
            writable: false
          });
        } catch {}

        function childFor(targetValue, property) {
          const child = make(`${path}.${String(property)}`);
          try {
            if (!Reflect.getOwnPropertyDescriptor(targetValue, property) && Reflect.isExtensible(targetValue)) {
              Reflect.defineProperty(targetValue, property, {
                configurable: true,
                enumerable: false,
                writable: true,
                value: child
              });
            }
          } catch {}
          return child;
        }

        proxy = new Proxy(target, {
          apply(_target, _thisArg, args) {
            try {
              if (options.queueCalls) queue.push(Array.from(args));
              const leaf = path.split('.').pop() || '';

              if (leaf === 'wrap' && typeof args[0] === 'function') return args[0];
              if (STRING_METHODS.has(leaf)) return '';
              if (BOOLEAN_METHODS.has(leaf)) return leaf !== 'hasOptedOutTracking';
              if (NUMBER_METHODS.has(leaf)) return 0;
              if (ARRAY_METHODS.has(leaf)) return [];

              if (CALLBACK_METHODS.has(leaf)) {
                const callback = [...args].reverse().find(value => typeof value === 'function');
                if (callback) {
                  try {
                    const result = callback(proxy);
                    return result === undefined ? proxy : result;
                  } catch {
                    return proxy;
                  }
                }
              }
            } catch {}
            return proxy;
          },
          construct() {
            return proxy;
          },
          get(targetValue, property, receiver) {
            try {
              if (property === MARK) return true;
              if (property === 'then') return undefined;
              if (property === 'toJSON') return emptyJson;
              if (property === 'toString') return nativeStringifier;
              if (property === 'valueOf') return zeroValue;
              if (property === Symbol.toPrimitive) return primitiveValue;
              if (property === Symbol.iterator) return emptyIterator;
              if (property === Symbol.asyncIterator) return emptyAsyncIterator;
              if (property === '__graxQueue') return queue;
              if ((property === 'q' || property === 'queue') && options.exposeQueue) return queue;
              if (property === 'loaded' || property === 'initialized' || property === 'isLoaded') return true;
              if (property === 'version') return options.version || '1.0';

              const ownDescriptor = Reflect.getOwnPropertyDescriptor(targetValue, property);
              if (ownDescriptor) {
                const ownValue = Reflect.get(targetValue, property, receiver);
                if (ownValue !== undefined) return ownValue;
              }
              return childFor(targetValue, property);
            } catch {
              return proxy;
            }
          },
          set(targetValue, property, value, receiver) {
            try {
              if ((property === 'q' || property === 'queue') && Array.isArray(value)) {
                queue.splice(0, queue.length, ...value);
              }
              return Reflect.set(targetValue, property, value, receiver);
            } catch {
              return true;
            }
          },
          defineProperty(targetValue, property, descriptor) {
            try { return Reflect.defineProperty(targetValue, property, descriptor); } catch { return true; }
          },
          deleteProperty(targetValue, property) {
            try { return Reflect.deleteProperty(targetValue, property); } catch { return true; }
          },
          getOwnPropertyDescriptor(targetValue, property) {
            try {
              const descriptor = Reflect.getOwnPropertyDescriptor(targetValue, property);
              if (descriptor) return descriptor;
              childFor(targetValue, property);
              return Reflect.getOwnPropertyDescriptor(targetValue, property);
            } catch {
              return undefined;
            }
          },
          ownKeys(targetValue) {
            try { return Reflect.ownKeys(targetValue); } catch { return []; }
          },
          getPrototypeOf() {
            return Function.prototype;
          },
          setPrototypeOf(targetValue, prototype) {
            try { return Reflect.setPrototypeOf(targetValue, prototype); } catch { return false; }
          },
          isExtensible(targetValue) {
            try { return Reflect.isExtensible(targetValue); } catch { return true; }
          },
          preventExtensions(targetValue) {
            try { return Reflect.preventExtensions(targetValue); } catch { return false; }
          },
          has() { return true; }
        });

        mark(proxy);
        cache.set(path, proxy);
        return proxy;
      };

      return make(label);
    }

    function descriptorValue(descriptor, name) {
      try {
        if (!descriptor) return undefined;
        if ('value' in descriptor) return descriptor.value;
        if (typeof descriptor.get === 'function') return ROOT[name];
      } catch {}
      return undefined;
    }

    function rememberAndDefine(name, value) {
      try {
        const current = Object.getOwnPropertyDescriptor(ROOT, name);
        const existing = descriptorValue(current, name);
        if (existing != null && !existing?.[MARK]) return existing;
        if (current?.configurable === false) return existing;
        if (!installed.has(name)) installed.set(name, current || null);
        Object.defineProperty(ROOT, name, {
          value,
          configurable: current ? current.configurable !== false : true,
          enumerable: current?.enumerable === true,
          writable: current && 'writable' in current ? current.writable !== false : true
        });
        return value;
      } catch {
        return undefined;
      }
    }

    function ensureArray(name) {
      try {
        if (Array.isArray(ROOT[name])) return ROOT[name];
        if (ROOT[name] != null && !ROOT[name]?.[MARK]) return ROOT[name];
      } catch {}
      return rememberAndDefine(name, mark([]));
    }

    function installCompatibilityObjects() {
      if (!protectionActive || (!mockObserved && !trackingFailureObserved)) return;

      try {
        installFunctionToStringMask();
        const dataLayer = ensureArray('dataLayer');
        ensureArray('_hsq');
        ensureArray('_paq');
        ensureArray('_gaq');

        if (typeof ROOT.gtag !== 'function') {
          const gtag = createRecursiveCallable('gtag', { queueCalls: true, exposeQueue: true });
          const wrapped = new Proxy(gtag, {
            apply(target, thisArg, args) {
              try { dataLayer?.push?.(Array.from(args)); } catch {}
              try { return Reflect.apply(target, thisArg, args); } catch { return target; }
            }
          });
          mark(wrapped);
          rememberAndDefine('gtag', wrapped);
        }

        if (typeof ROOT.ga !== 'function') {
          const ga = createRecursiveCallable('ga', { queueCalls: true, exposeQueue: true });
          try { ga.l = Date.now(); } catch {}
          rememberAndDefine('ga', ga);
        }

        if (typeof ROOT.fbq !== 'function') {
          const fbq = createRecursiveCallable('fbq', {
            queueCalls: true,
            exposeQueue: true,
            version: '2.0'
          });
          try {
            fbq.loaded = true;
            fbq.version = '2.0';
            fbq.callMethod = fbq;
          } catch {}
          rememberAndDefine('fbq', fbq);
          rememberAndDefine('_fbq', fbq);
        }

        for (const name of GLOBAL_NAMES) {
          let current;
          try { current = ROOT[name]; } catch {}
          if (current == null || current?.[MARK]) {
            rememberAndDefine(name, createRecursiveCallable(name, {
              queueCalls: true,
              exposeQueue: true
            }));
          }
        }
      } catch {}
    }

    function removeCompatibilityObjects() {
      for (const [name, previous] of installed) {
        try {
          const current = Object.getOwnPropertyDescriptor(ROOT, name);
          const value = descriptorValue(current, name);
          if (!value?.[MARK]) continue;
          if (previous) Object.defineProperty(ROOT, name, previous);
          else delete ROOT[name];
        } catch {}
      }
      installed.clear();
      restoreFunctionToStringMask();
    }

    function setActive(next) {
      protectionActive = Boolean(next);
      if (protectionActive) installCompatibilityObjects();
      else removeCompatibilityObjects();
    }

    function eventFailureText(event) {
      try {
        const error = event?.error || event?.reason;
        return `${event?.message || ''} ${error?.message || error || ''} ${error?.stack || ''}`;
      } catch {
        return '';
      }
    }

    function isTrackingRuntimeFailure(event) {
      try {
        const text = eventFailureText(event);
        return TRACKING_HINT.test(text) && TRACKING_RUNTIME_FAILURE.test(text);
      } catch {
        return false;
      }
    }

    function recoverTrackingRuntimeFailure(event) {
      try {
        if (!isTrackingRuntimeFailure(event)) return false;
        trackingFailureObserved = true;
        installCompatibilityObjects();
        event?.preventDefault?.();
        return true;
      } catch {
        return false;
      }
    }

    try {
      nativeAddEventListener.call(document, STATE_EVENT, event => {
        try { setActive(event?.detail?.enabled === true); } catch {}
      }, { capture: true });
    } catch {}

    try {
      nativeAddEventListener.call(ROOT, MOCK_READY_EVENT, () => {
        try {
          mockObserved = true;
          installCompatibilityObjects();
        } catch {}
      }, { capture: true });
    } catch {}

    try {
      nativeAddEventListener.call(ROOT, 'error', event => {
        try {
          const target = event?.target;
          if (target?.tagName === 'SCRIPT' && isTrackingUrl(target.src || '')) {
            trackingFailureObserved = true;
            installCompatibilityObjects();
            event.preventDefault?.();
            return;
          }
          recoverTrackingRuntimeFailure(event);
        } catch {}
      }, { capture: true });
    } catch {}

    try {
      nativeAddEventListener.call(ROOT, 'unhandledrejection', event => {
        try { recoverTrackingRuntimeFailure(event); } catch {}
      }, { capture: true });
    } catch {}
  } catch {}
})();
