// DOM mutation tracking module for DevTool
// Tracks added, removed, and modified elements with visual highlighting
//
// INDUSTRIAL-STRENGTH ERROR HANDLING:
// - Top-level error boundary
// - Dependency validation
// - Safe MutationObserver with feature detection
// - All DOM operations wrapped in try-catch
// - Graceful degradation on failures

(function() {
  'use strict';

  // Top-level error boundary
  try {
    // Dependency validation
    var utils = window.__devtool_utils;
    var core = window.__devtool_core;

    if (!utils || typeof utils.generateSelector !== 'function') {
      console.error('[DevTool][Mutation] Missing or invalid utils dependency');
      return;
    }

    if (!core || typeof core.send !== 'function') {
      console.error('[DevTool][Mutation] Missing or invalid core dependency');
      return;
    }

    // Feature detection
    var hasMutationObserver = typeof MutationObserver !== 'undefined';
    var hasMap = typeof Map !== 'undefined';

    if (!hasMutationObserver) {
      console.warn('[DevTool][Mutation] MutationObserver not supported - tracking disabled');
      return;
    }

    // Error reporting
    function reportError(context, error) {
      try {
        if (core && typeof core.reportError === 'function') {
          core.reportError('[Mutation] ' + context, error);
        } else {
          console.error('[DevTool][Mutation]', context, error);
        }
      } catch (e) {
        console.error('[DevTool][Mutation] Error reporting failed:', e);
      }
    }

    // Configuration with safe defaults
    var config = {
      maxHistorySize: 200,
      highlightDuration: 2000,
      highlightAddedColor: 'rgba(0, 255, 0, 0.2)',
      highlightRemovedColor: 'rgba(255, 0, 0, 0.2)',
      highlightModifiedColor: 'rgba(255, 255, 0, 0.2)',
      trackAttributes: true,
      trackCharacterData: false,
      enableHighlighting: false,  // OFF by default - enable via API (React-friendly)
      ignoreSelectors: ['.__devtool', '#__devtool-overlays', 'script', 'style', 'link'],
      sendBatchSize: 10,
      sendInterval: 1000
    };

    var mutations = [];
    var pendingBatch = [];
    var highlightElements = hasMap ? new Map() : null;
    var highlightFallback = []; // Fallback if Map not available
    var observer = null;
    var batchTimer = null;

    // Max mutation rate tracking (starts after page load settles)
    var maxRateTracking = false;
    var maxRate = 0;
    var maxRateTimestamp = 0;
    var maxRateWindow = 1000; // Track max over 1s windows
    var rateCheckInterval = null;

    // Safe element ignore check
    function shouldIgnore(node) {
      if (!node) return true;
      if (!(node instanceof HTMLElement)) return true;

      try {
        for (var i = 0; i < config.ignoreSelectors.length; i++) {
          try {
            if (node.matches && typeof node.matches === 'function') {
              if (node.matches(config.ignoreSelectors[i])) return true;
            }
            if (node.closest && typeof node.closest === 'function') {
              if (node.closest(config.ignoreSelectors[i])) return true;
            }
          } catch (e) {
            // Invalid selector - skip
          }
        }
      } catch (e) {
        reportError('shouldIgnore_failed', e);
      }

      return false;
    }

    // Safe highlight with full error handling
    function highlightMutation(element, color) {
      // Check if highlighting is enabled
      if (!config.enableHighlighting) return;

      if (!element || !(element instanceof HTMLElement)) return;
      if (shouldIgnore(element)) return;
      if (typeof color !== 'string') return;

      try {
        if (!element.style) return;

        var originalBg = element.style.backgroundColor || '';
        var originalOutline = element.style.outline || '';
        var originalTransition = element.style.transition || '';

        // Apply highlight styles
        try {
          element.style.transition = 'background-color 0.3s, outline 0.3s';
          element.style.backgroundColor = color;

          try {
            var outlineColor = color.replace('0.2', '0.8');
            element.style.outline = '2px solid ' + outlineColor;
          } catch (e) {
            // Color replace failed - use original
            element.style.outline = '2px solid ' + color;
          }
        } catch (e) {
          reportError('highlight_style_apply_failed', e);
          return;
        }

        // Store for cleanup
        var id = 'mutation-' + Date.now() + '-' + Math.random();
        var highlightInfo = {
          element: element,
          originalBg: originalBg,
          originalOutline: originalOutline,
          originalTransition: originalTransition
        };

        if (highlightElements) {
          highlightElements.set(id, highlightInfo);
        } else {
          highlightFallback.push({ id: id, info: highlightInfo });
        }

        // Schedule cleanup
        setTimeout(function() {
          try {
            var info = null;

            if (highlightElements) {
              info = highlightElements.get(id);
              highlightElements.delete(id);
            } else {
              for (var i = 0; i < highlightFallback.length; i++) {
                if (highlightFallback[i].id === id) {
                  info = highlightFallback[i].info;
                  highlightFallback.splice(i, 1);
                  break;
                }
              }
            }

            if (info && info.element && info.element.style) {
              try {
                info.element.style.backgroundColor = info.originalBg;
                info.element.style.outline = info.originalOutline;

                setTimeout(function() {
                  try {
                    if (info.element && info.element.style) {
                      info.element.style.transition = info.originalTransition;
                    }
                  } catch (e) {
                    // Element may be removed - ignore
                  }
                }, 300);
              } catch (e) {
                // Style restoration failed - ignore
              }
            }
          } catch (e) {
            reportError('highlight_cleanup_failed', e);
          }
        }, config.highlightDuration);

      } catch (e) {
        reportError('highlightMutation_failed', e);
      }
    }

    // Safe selector generation
    function safeGenerateSelector(element) {
      try {
        if (!element || typeof utils.generateSelector !== 'function') {
          return null;
        }
        return utils.generateSelector(element);
      } catch (e) {
        reportError('selector_generation_failed', e);
        return null;
      }
    }

    // Safe NodeList to Array conversion
    function nodeListToArray(nodeList) {
      if (!nodeList) return [];

      try {
        if (Array.isArray(nodeList)) return nodeList;

        var arr = [];
        for (var i = 0; i < nodeList.length; i++) {
          arr.push(nodeList[i]);
        }
        return arr;
      } catch (e) {
        reportError('nodeList_conversion_failed', e);
        return [];
      }
    }

    // Find triggering interaction for a mutation
    // Returns the most recent interaction within the correlation window (500ms)
    function findTriggeringInteraction(timestamp) {
      try {
        // Check if interactions module is available
        if (!window.__devtool_interactions || typeof window.__devtool_interactions.getHistory !== 'function') {
          return null;
        }

        var correlationWindow = 500; // 500ms window
        var windowStart = timestamp - correlationWindow;

        // Get recent interactions
        var interactions = window.__devtool_interactions.getHistory(20);
        if (!interactions || interactions.length === 0) return null;

        // Find most recent interaction before this mutation
        for (var i = interactions.length - 1; i >= 0; i--) {
          var interaction = interactions[i];
          if (interaction && interaction.timestamp <= timestamp && interaction.timestamp >= windowStart) {
            return {
              type: interaction.event_type,
              timestamp: interaction.timestamp,
              latency: timestamp - interaction.timestamp,
              target: interaction.target ? interaction.target.selector : null
            };
          }
        }

        return null;
      } catch (e) {
        // Silently ignore - correlation is optional
        return null;
      }
    }

    // Mutation observer callback with comprehensive error handling
    function handleMutations(mutationsList) {
      if (!mutationsList || mutationsList.length === 0) return;

      try {
        for (var i = 0; i < mutationsList.length; i++) {
          try {
            var mutation = mutationsList[i];
            if (!mutation) continue;

            // Handle added/removed nodes
            if (mutation.type === 'childList') {
              try {
                // Added nodes
                var addedNodes = nodeListToArray(mutation.addedNodes);
                for (var j = 0; j < addedNodes.length; j++) {
                  try {
                    var node = addedNodes[j];
                    if (shouldIgnore(node)) continue;

                    var now = Date.now();
                    var triggeredBy = findTriggeringInteraction(now);

                    var record = {
                      mutation_type: 'added',
                      target: {
                        selector: safeGenerateSelector(mutation.target),
                        tag: mutation.target.tagName ? mutation.target.tagName.toLowerCase() : 'unknown',
                        id: mutation.target.id || undefined
                      },
                      added: [{
                        selector: node.nodeType === 1 ? safeGenerateSelector(node) : null,
                        tag: node.nodeName ? node.nodeName.toLowerCase() : 'unknown',
                        id: node.id || undefined,
                        html: node.outerHTML ? node.outerHTML.substring(0, 500) : undefined
                      }],
                      timestamp: now,
                      triggered_by: triggeredBy
                    };

                    mutations.push(record);
                    pendingBatch.push(record);

                    if (node instanceof HTMLElement) {
                      highlightMutation(node, config.highlightAddedColor);
                    }
                  } catch (e) {
                    reportError('added_node_processing_failed', e);
                  }
                }

                // Removed nodes
                var removedNodes = nodeListToArray(mutation.removedNodes);
                for (var k = 0; k < removedNodes.length; k++) {
                  try {
                    var rnode = removedNodes[k];
                    if (shouldIgnore(rnode)) continue;

                    var rNow = Date.now();
                    var rTriggeredBy = findTriggeringInteraction(rNow);

                    var rrecord = {
                      mutation_type: 'removed',
                      target: {
                        selector: safeGenerateSelector(mutation.target),
                        tag: mutation.target.tagName ? mutation.target.tagName.toLowerCase() : 'unknown',
                        id: mutation.target.id || undefined
                      },
                      removed: [{
                        tag: rnode.nodeName ? rnode.nodeName.toLowerCase() : 'unknown',
                        id: rnode.id || undefined,
                        html: rnode.outerHTML ? rnode.outerHTML.substring(0, 200) : undefined
                      }],
                      timestamp: rNow,
                      triggered_by: rTriggeredBy
                    };

                    mutations.push(rrecord);
                    pendingBatch.push(rrecord);
                  } catch (e) {
                    reportError('removed_node_processing_failed', e);
                  }
                }
              } catch (e) {
                reportError('childList_mutation_failed', e);
              }
            }

            // Handle attribute changes
            if (mutation.type === 'attributes' && config.trackAttributes) {
              try {
                var target = mutation.target;
                if (shouldIgnore(target)) continue;

                var attrValue = null;
                try {
                  if (target && typeof target.getAttribute === 'function' && mutation.attributeName) {
                    attrValue = target.getAttribute(mutation.attributeName);
                  }
                } catch (e) {
                  // getAttribute failed - use null
                }

                var aNow = Date.now();
                var aTriggeredBy = findTriggeringInteraction(aNow);

                var arecord = {
                  mutation_type: 'attributes',
                  target: {
                    selector: safeGenerateSelector(target),
                    tag: target.tagName ? target.tagName.toLowerCase() : 'unknown',
                    id: target.id || undefined
                  },
                  attribute: {
                    name: mutation.attributeName || 'unknown',
                    old_value: mutation.oldValue || null,
                    new_value: attrValue
                  },
                  timestamp: aNow,
                  triggered_by: aTriggeredBy
                };

                mutations.push(arecord);
                pendingBatch.push(arecord);
                highlightMutation(target, config.highlightModifiedColor);
              } catch (e) {
                reportError('attribute_mutation_failed', e);
              }
            }
          } catch (e) {
            reportError('mutation_processing_failed', e);
          }
        }

        // Trim history
        try {
          if (mutations.length > config.maxHistorySize) {
            mutations = mutations.slice(-config.maxHistorySize);
          }
        } catch (e) {
          reportError('history_trim_failed', e);
        }

      } catch (e) {
        reportError('handleMutations_failed', e);
      }
    }

    // Safe batch send
    function sendBatch() {
      try {
        if (pendingBatch.length === 0) return;

        var batch = pendingBatch.splice(0, config.sendBatchSize);

        if (core && typeof core.send === 'function') {
          core.send('mutations', { events: batch });
        }
      } catch (e) {
        reportError('sendBatch_failed', e);
      }
    }

    // Safe observer start
    function startObserver() {
      try {
        if (observer) return;

        if (!hasMutationObserver) {
          console.warn('[DevTool][Mutation] MutationObserver not available');
          return;
        }

        if (!document.body) {
          console.warn('[DevTool][Mutation] document.body not available');
          return;
        }

        // Create observer with wrapped callback
        try {
          observer = new MutationObserver(function(mutations) {
            try {
              handleMutations(mutations);
            } catch (e) {
              reportError('observer_callback_failed', e);
            }
          });
        } catch (e) {
          reportError('observer_creation_failed', e);
          return;
        }

        // Configure options with validation
        var options = {
          childList: true,
          subtree: true,
          attributes: config.trackAttributes,
          attributeOldValue: config.trackAttributes, // Fixed: match attributes setting
          characterData: config.trackCharacterData,
          characterDataOldValue: config.trackCharacterData // Fixed: match characterData setting
        };

        // Start observing with validation
        try {
          observer.observe(document.body, options);
        } catch (e) {
          reportError('observer_observe_failed', e);
          observer = null;
        }

      } catch (e) {
        reportError('startObserver_failed', e);
      }
    }

    // Safe observer stop
    function stopObserver() {
      try {
        if (observer && typeof observer.disconnect === 'function') {
          observer.disconnect();
          observer = null;
        }
      } catch (e) {
        reportError('stopObserver_failed', e);
      }
    }

    // Start batch sender with error handling
    try {
      batchTimer = setInterval(function() {
        try {
          sendBatch();
        } catch (e) {
          reportError('batch_timer_failed', e);
        }
      }, config.sendInterval);
    } catch (e) {
      reportError('setInterval_failed', e);
    }

    // Start max rate tracking (checks current rate and updates max)
    function startMaxRateTracking() {
      try {
        maxRateTracking = true;

        rateCheckInterval = setInterval(function() {
          try {
            if (!maxRateTracking) return;

            var now = Date.now();
            var windowStart = now - maxRateWindow;
            var count = 0;

            // Count mutations in last window (from end for efficiency)
            for (var i = mutations.length - 1; i >= 0; i--) {
              if (mutations[i].timestamp < windowStart) break;
              count++;
            }

            var rate = count / (maxRateWindow / 1000); // mutations per second

            if (rate > maxRate) {
              maxRate = rate;
              maxRateTimestamp = now;
            }
          } catch (e) {
            reportError('rate_check_failed', e);
          }
        }, 1000); // Check every second
      } catch (e) {
        reportError('startMaxRateTracking_failed', e);
      }
    }

    // Initialize when DOM is ready
    try {
      if (document.body) {
        startObserver();

        // Start max rate tracking after 3 seconds (let initial render settle)
        setTimeout(function() {
          try {
            startMaxRateTracking();
          } catch (e) {
            reportError('delayed_max_tracking_start_failed', e);
          }
        }, 3000);
      } else {
        if (typeof document.addEventListener === 'function') {
          document.addEventListener('DOMContentLoaded', function() {
            try {
              startObserver();

              // Start max rate tracking after 3 seconds
              setTimeout(function() {
                try {
                  startMaxRateTracking();
                } catch (e) {
                  reportError('delayed_max_tracking_start_failed', e);
                }
              }, 3000);
            } catch (e) {
              reportError('DOMContentLoaded_handler_failed', e);
            }
          });
        }
      }
    } catch (e) {
      reportError('initialization_failed', e);
    }

    // ===================================================================
    // SPINNER / LOADING-INDICATOR OBSERVER (worktrack C1)
    // -------------------------------------------------------------------
    // Self-contained, dedicated observer that tracks when loading
    // indicators (spinners, skeletons, progress bars) appear and
    // disappear in the DOM, building a timeline with timestamps. A later
    // slice (C2 audit-loading.js) reads window.__devtool_spinners to
    // detect serial "cascades" and concurrent "fragmentation". Each
    // spinner's active interval is correlated with pending API calls
    // from window.__devtool_api at disappear time.
    //
    // ISOLATION: this block keeps its OWN state (spinnerTimeline,
    // spinnerActive WeakMap, spinnerObserver) and does NOT feed into the
    // general mutation batch pipeline (handleMutations/sendBatch/
    // window.__devtool_mutations). It only reuses the stateless helpers
    // shouldIgnore / safeGenerateSelector / reportError.
    // ===================================================================

    var spinnerConfig = {
      maxTimeline: 500,          // cap recorded events (drop oldest)
      maxPendingAPI: 10,         // cap correlated api calls per record
      maxScanNodes: 300,         // cap querySelectorAll fan-out per added node
      nameRegex: /(spin|load|skeleton|shimmer|pending|placeholder)/,
      animRegex: /(spin|rotate|load|shimmer|pulse)/i
    };

    var hasWeakMap = typeof WeakMap !== 'undefined';
    var spinnerTimeline = [];                                  // completed + active records
    var spinnerActive = hasWeakMap ? new WeakMap() : null;     // element -> record
    var spinnerObserver = null;
    var spinnerCounter = 0;                                    // monotonic id disambiguator

    // Heuristic: is this element a loading indicator?
    function isSpinner(el) {
      try {
        if (!el || el.nodeType !== 1) return false;

        // aria-busy
        try {
          if (el.getAttribute && el.getAttribute('aria-busy') === 'true') return true;
        } catch (e) { /* ignore */ }

        // role
        try {
          var role = el.getAttribute ? el.getAttribute('role') : null;
          if (role === 'progressbar' || role === 'status') return true;
        } catch (e) { /* ignore */ }

        // <progress>
        try {
          if (el.tagName && el.tagName.toLowerCase() === 'progress') return true;
        } catch (e) { /* ignore */ }

        // class / id / aria-label name match
        try {
          var cls = (el.className && typeof el.className === 'string') ? el.className : '';
          var id = el.id || '';
          var label = (el.getAttribute && el.getAttribute('aria-label')) || '';
          var hay = (cls + ' ' + id + ' ' + label).toLowerCase();
          if (hay && spinnerConfig.nameRegex.test(hay)) return true;
        } catch (e) { /* ignore */ }

        // CSS animation name (best-effort, names only — no keyframe parsing)
        try {
          if (typeof getComputedStyle === 'function') {
            var animName = getComputedStyle(el).animationName;
            if (animName && animName !== 'none' && spinnerConfig.animRegex.test(animName)) {
              return true;
            }
          }
        } catch (e) { /* ignore */ }

        return false;
      } catch (e) {
        reportError('isSpinner_failed', e);
        return false;
      }
    }

    // Build a cheap ancestor path (up to ~4 levels) of tag#id.class tokens.
    function spinnerAncestorPath(el) {
      var path = [];
      try {
        var cur = el ? el.parentElement : null;
        var levels = 0;
        while (cur && levels < 4) {
          try {
            var token = cur.tagName ? cur.tagName.toLowerCase() : 'node';
            if (cur.id) {
              token += '#' + cur.id;
            } else if (cur.className && typeof cur.className === 'string') {
              var first = cur.className.split(/\s+/)[0];
              if (first) token += '.' + first;
            }
            path.push(token);
          } catch (e) { /* ignore one level */ }
          cur = cur.parentElement;
          levels++;
        }
      } catch (e) {
        reportError('spinnerAncestorPath_failed', e);
      }
      return path;
    }

    // Correlate a finished spinner window with pending api-tracker calls.
    function spinnerPendingAPI(appearedAt, disappearedAt) {
      var out = [];
      try {
        if (!window.__devtool_api || typeof window.__devtool_api.getCalls !== 'function') {
          return out;
        }
        var calls = window.__devtool_api.getCalls();
        if (!calls || !calls.length) return out;

        var end = (typeof disappearedAt === 'number') ? disappearedAt : Date.now();
        for (var i = 0; i < calls.length; i++) {
          try {
            var c = calls[i];
            if (!c || typeof c.timestamp !== 'number') continue;
            var cStart = c.timestamp;
            var cEnd = cStart + (typeof c.duration === 'number' ? c.duration : 0);
            // overlap test: [cStart,cEnd] intersects [appearedAt,end]
            if (cEnd >= appearedAt && cStart <= end) {
              out.push({
                url: c.url,
                method: c.method,
                status: c.status,
                duration: c.duration,
                timestamp: c.timestamp
              });
              if (out.length >= spinnerConfig.maxPendingAPI) break;
            }
          } catch (e) { /* skip one call */ }
        }
      } catch (e) {
        reportError('spinnerPendingAPI_failed', e);
      }
      return out;
    }

    function spinnerTrimTimeline() {
      try {
        if (spinnerTimeline.length > spinnerConfig.maxTimeline) {
          spinnerTimeline = spinnerTimeline.slice(-spinnerConfig.maxTimeline);
        }
      } catch (e) {
        reportError('spinnerTrimTimeline_failed', e);
      }
    }

    // Record an element that just became a spinner (added or attr-toggled).
    function spinnerAppear(el) {
      try {
        if (!el || el.nodeType !== 1) return;
        if (shouldIgnore(el)) return;
        if (spinnerActive && spinnerActive.has(el)) return; // already active

        var now = Date.now();
        spinnerCounter++;
        var sel = safeGenerateSelector(el);
        var record = {
          id: (sel || 'spinner') + '#' + spinnerCounter,
          selector: sel,
          ancestorPath: spinnerAncestorPath(el),
          appearedAt: now,
          disappearedAt: null,
          pendingAPI: null
        };

        if (spinnerActive) {
          spinnerActive.set(el, record);
        }
        spinnerTimeline.push(record);
        spinnerTrimTimeline();
      } catch (e) {
        reportError('spinnerAppear_failed', e);
      }
    }

    // Finalize an element that stopped being a spinner (removed or toggled off).
    function spinnerDisappear(el) {
      try {
        if (!el || el.nodeType !== 1) return;
        if (!spinnerActive) return;
        var record = spinnerActive.get(el);
        if (!record) return;

        record.disappearedAt = Date.now();
        record.pendingAPI = spinnerPendingAPI(record.appearedAt, record.disappearedAt);
        spinnerActive['delete'](el);
      } catch (e) {
        reportError('spinnerDisappear_failed', e);
      }
    }

    // Walk an added subtree (self + descendants) for spinners, capped.
    function spinnerScanAdded(node) {
      try {
        if (!node || node.nodeType !== 1) return;
        if (shouldIgnore(node)) return;

        if (isSpinner(node)) spinnerAppear(node);

        if (typeof node.querySelectorAll === 'function') {
          var kids = node.querySelectorAll('*');
          var limit = Math.min(kids.length, spinnerConfig.maxScanNodes);
          for (var i = 0; i < limit; i++) {
            try {
              var kid = kids[i];
              if (shouldIgnore(kid)) continue;
              if (isSpinner(kid)) spinnerAppear(kid);
            } catch (e) { /* skip one kid */ }
          }
        }
      } catch (e) {
        reportError('spinnerScanAdded_failed', e);
      }
    }

    // Walk a removed subtree (self + descendants) to finalize active spinners.
    function spinnerScanRemoved(node) {
      try {
        if (!node || node.nodeType !== 1) return;

        if (spinnerActive && spinnerActive.has(node)) spinnerDisappear(node);

        if (typeof node.querySelectorAll === 'function') {
          var kids = node.querySelectorAll('*');
          var limit = Math.min(kids.length, spinnerConfig.maxScanNodes);
          for (var i = 0; i < limit; i++) {
            try {
              var kid = kids[i];
              if (spinnerActive && spinnerActive.has(kid)) spinnerDisappear(kid);
            } catch (e) { /* skip one kid */ }
          }
        }
      } catch (e) {
        reportError('spinnerScanRemoved_failed', e);
      }
    }

    // Dedicated spinner mutation handler (separate from handleMutations).
    function handleSpinnerMutations(mutationsList) {
      if (!mutationsList || !mutationsList.length) return;
      try {
        for (var i = 0; i < mutationsList.length; i++) {
          try {
            var mutation = mutationsList[i];
            if (!mutation) continue;

            if (mutation.type === 'childList') {
              var added = nodeListToArray(mutation.addedNodes);
              for (var a = 0; a < added.length; a++) {
                spinnerScanAdded(added[a]);
              }
              var removed = nodeListToArray(mutation.removedNodes);
              for (var r = 0; r < removed.length; r++) {
                spinnerScanRemoved(removed[r]);
              }
            } else if (mutation.type === 'attributes') {
              // class / aria-busy / role toggle -> appear or disappear
              var t = mutation.target;
              if (!t || t.nodeType !== 1) continue;
              if (shouldIgnore(t)) continue;
              var nowSpinner = isSpinner(t);
              var wasActive = spinnerActive && spinnerActive.has(t);
              if (nowSpinner && !wasActive) {
                spinnerAppear(t);
              } else if (!nowSpinner && wasActive) {
                spinnerDisappear(t);
              }
            }
          } catch (e) {
            reportError('spinner_mutation_processing_failed', e);
          }
        }
      } catch (e) {
        reportError('handleSpinnerMutations_failed', e);
      }
    }

    function startSpinnerObserver() {
      try {
        if (spinnerObserver) return;
        if (!hasMutationObserver || !document.body) return;
        if (!hasWeakMap) {
          // Without WeakMap we cannot reliably pair appear/disappear; bail loudly.
          reportError('spinner_observer_requires_weakmap',
            new Error('WeakMap unavailable - spinner tracking disabled'));
          return;
        }

        spinnerObserver = new MutationObserver(function(list) {
          try {
            handleSpinnerMutations(list);
          } catch (e) {
            reportError('spinner_observer_callback_failed', e);
          }
        });

        spinnerObserver.observe(document.body, {
          childList: true,
          subtree: true,
          attributes: true,
          attributeFilter: ['class', 'aria-busy', 'role']
        });

        // Seed: scan existing DOM for spinners already present at start.
        try {
          spinnerScanAdded(document.body);
        } catch (e) {
          reportError('spinner_initial_scan_failed', e);
        }
      } catch (e) {
        reportError('startSpinnerObserver_failed', e);
        spinnerObserver = null;
      }
    }

    function stopSpinnerObserver() {
      try {
        if (spinnerObserver && typeof spinnerObserver.disconnect === 'function') {
          spinnerObserver.disconnect();
        }
        spinnerObserver = null;
      } catch (e) {
        reportError('stopSpinnerObserver_failed', e);
      }
    }

    // Auto-start the spinner observer alongside the main observer.
    try {
      if (document.body) {
        startSpinnerObserver();
      } else if (typeof document.addEventListener === 'function') {
        document.addEventListener('DOMContentLoaded', function() {
          try {
            startSpinnerObserver();
          } catch (e) {
            reportError('spinner_domcontentloaded_failed', e);
          }
        });
      }
    } catch (e) {
      reportError('spinner_initialization_failed', e);
    }

    // Export spinner timeline API.
    try {
      if (!window.__devtool_spinners) {
        window.__devtool_spinners = {
          // Most-recent-friendly ordering: newest events first.
          getTimeline: function() {
            try {
              return spinnerTimeline.slice().reverse();
            } catch (e) {
              reportError('spinner_getTimeline_failed', e);
              return [];
            }
          },

          start: function() {
            try {
              startSpinnerObserver();
            } catch (e) {
              reportError('spinner_start_failed', e);
            }
          },

          stop: function() {
            try {
              stopSpinnerObserver();
            } catch (e) {
              reportError('spinner_stop_failed', e);
            }
          },

          clear: function() {
            try {
              spinnerTimeline = [];
              if (hasWeakMap) {
                spinnerActive = new WeakMap();
              }
              spinnerCounter = 0;
            } catch (e) {
              reportError('spinner_clear_failed', e);
            }
          },

          isActive: function() {
            return !!spinnerObserver;
          }
        };
      }
    } catch (e) {
      console.error('[DevTool][Mutation] Failed to export spinner API:', e);
    }

    // Export mutations API with input validation
    try {
      if (!window.__devtool_mutations) {
        window.__devtool_mutations = {
          getHistory: function(count) {
            try {
              count = typeof count === 'number' ? count : 50;
              if (count < 0) count = 50;

              var start = Math.max(0, mutations.length - count);
              return mutations.slice(start);
            } catch (e) {
              reportError('getHistory_failed', e);
              return [];
            }
          },

          getAdded: function(since) {
            try {
              since = typeof since === 'number' ? since : 0;

              return mutations.filter(function(m) {
                try {
                  return m && m.mutation_type === 'added' && m.timestamp > since;
                } catch (e) {
                  return false;
                }
              });
            } catch (e) {
              reportError('getAdded_failed', e);
              return [];
            }
          },

          getRemoved: function(since) {
            try {
              since = typeof since === 'number' ? since : 0;

              return mutations.filter(function(m) {
                try {
                  return m && m.mutation_type === 'removed' && m.timestamp > since;
                } catch (e) {
                  return false;
                }
              });
            } catch (e) {
              reportError('getRemoved_failed', e);
              return [];
            }
          },

          getModified: function(since) {
            try {
              since = typeof since === 'number' ? since : 0;

              return mutations.filter(function(m) {
                try {
                  return m && m.mutation_type === 'attributes' && m.timestamp > since;
                } catch (e) {
                  return false;
                }
              });
            } catch (e) {
              reportError('getModified_failed', e);
              return [];
            }
          },

          highlightRecent: function(duration) {
            try {
              duration = typeof duration === 'number' ? duration : 5000;
              if (duration < 0) duration = 5000;

              var since = Date.now() - duration;

              for (var i = 0; i < mutations.length; i++) {
                try {
                  var m = mutations[i];
                  if (m && m.timestamp > since && m.mutation_type === 'added' && m.added) {
                    for (var j = 0; j < m.added.length; j++) {
                      try {
                        var node = m.added[j];
                        if (node && node.selector) {
                          var el = document.querySelector(node.selector);
                          if (el) {
                            highlightMutation(el, config.highlightAddedColor);
                          }
                        }
                      } catch (e) {
                        // querySelector failed or highlight failed - skip
                      }
                    }
                  }
                } catch (e) {
                  // Mutation processing failed - skip
                }
              }
            } catch (e) {
              reportError('highlightRecent_failed', e);
            }
          },

          clear: function() {
            try {
              mutations = [];
              pendingBatch = [];
            } catch (e) {
              reportError('clear_failed', e);
            }
          },

          pause: function() {
            try {
              stopObserver();
            } catch (e) {
              reportError('pause_failed', e);
            }
          },

          resume: function() {
            try {
              startObserver();
            } catch (e) {
              reportError('resume_failed', e);
            }
          },

          enableHighlighting: function() {
            try {
              config.enableHighlighting = true;
            } catch (e) {
              reportError('enableHighlighting_failed', e);
            }
          },

          disableHighlighting: function() {
            try {
              config.enableHighlighting = false;
            } catch (e) {
              reportError('disableHighlighting_failed', e);
            }
          },

          getRateStats: function(windows) {
            try {
              // Default windows: 1s, 5s, 30s
              windows = windows || [1000, 5000, 30000];

              var now = Date.now();
              var rates = {};
              var counts = {};

              // Count mutations in each window
              for (var i = 0; i < windows.length; i++) {
                var windowMs = windows[i];
                var windowStart = now - windowMs;
                var count = 0;

                // Count from end (most recent) for efficiency
                for (var j = mutations.length - 1; j >= 0; j--) {
                  if (mutations[j].timestamp < windowStart) break;
                  count++;
                }

                var label = windowMs < 1000 ? windowMs + 'ms' : (windowMs / 1000) + 's';
                counts[label] = count;
                rates[label] = count / (windowMs / 1000); // mutations per second
              }

              // Calculate acceleration ratios
              var acceleration = {};
              var labels = Object.keys(rates);

              for (var k = 0; k < labels.length - 1; k++) {
                var shortLabel = labels[k];
                var longLabel = labels[k + 1];
                var ratio = rates[shortLabel] / (rates[longLabel] || 0.001); // avoid divide by zero
                acceleration[shortLabel + '/' + longLabel] = Math.round(ratio * 100) / 100;
              }

              // Determine status
              var primaryRatio = acceleration[labels[0] + '/' + labels[1]] || 1;
              var status = primaryRatio > 1.5 ? 'accelerating' :
                           primaryRatio < 0.7 ? 'decelerating' : 'steady';

              // Health check
              var currentRate = rates[labels[0]] || 0;
              var health = currentRate > 50 ? 'critical' :
                           currentRate > 20 ? 'warning' : 'ok';

              return {
                windows: rates,
                counts: counts,
                acceleration: acceleration,
                status: status,
                health: health,
                max: {
                  rate: Math.round(maxRate * 100) / 100,
                  timestamp: maxRateTimestamp,
                  ago: maxRateTimestamp ? Math.round((now - maxRateTimestamp) / 1000) + 's' : 'n/a'
                }
              };

            } catch (e) {
              reportError('getRateStats_failed', e);
              return { error: e.message || 'getRateStats failed' };
            }
          },

          // Get mutations triggered by specific interaction type
          getTriggeredBy: function(interactionType) {
            try {
              if (typeof interactionType !== 'string') {
                return { error: 'Invalid interaction type' };
              }

              var results = [];
              for (var i = 0; i < mutations.length; i++) {
                try {
                  var m = mutations[i];
                  if (m && m.triggered_by && m.triggered_by.type === interactionType) {
                    results.push(m);
                  }
                } catch (e) {
                  // Skip invalid mutation
                }
              }

              return results;
            } catch (e) {
              reportError('getTriggeredBy_failed', e);
              return { error: e.message || 'getTriggeredBy failed' };
            }
          },

          // Get mutations with no triggering interaction (spontaneous updates)
          getUntriggered: function() {
            try {
              var results = [];
              for (var i = 0; i < mutations.length; i++) {
                try {
                  var m = mutations[i];
                  if (m && !m.triggered_by) {
                    results.push(m);
                  }
                } catch (e) {
                  // Skip invalid mutation
                }
              }

              return results;
            } catch (e) {
              reportError('getUntriggered_failed', e);
              return { error: e.message || 'getUntriggered failed' };
            }
          },

          // Get correlation statistics
          getCorrelationStats: function() {
            try {
              var stats = {
                total: mutations.length,
                triggered: 0,
                untriggered: 0,
                by_type: {},
                avg_latency: {},
                max_latency: {}
              };

              var latencySum = {};
              var latencyCount = {};
              var latencyMax = {};

              for (var i = 0; i < mutations.length; i++) {
                try {
                  var m = mutations[i];
                  if (!m) continue;

                  if (m.triggered_by) {
                    stats.triggered++;
                    var type = m.triggered_by.type;

                    // Count by type
                    stats.by_type[type] = (stats.by_type[type] || 0) + 1;

                    // Track latency
                    if (typeof m.triggered_by.latency === 'number') {
                      latencySum[type] = (latencySum[type] || 0) + m.triggered_by.latency;
                      latencyCount[type] = (latencyCount[type] || 0) + 1;
                      latencyMax[type] = Math.max(latencyMax[type] || 0, m.triggered_by.latency);
                    }
                  } else {
                    stats.untriggered++;
                  }
                } catch (e) {
                  // Skip invalid mutation
                }
              }

              // Calculate averages
              for (var type in latencySum) {
                if (latencyCount[type] > 0) {
                  stats.avg_latency[type] = Math.round(latencySum[type] / latencyCount[type]);
                  stats.max_latency[type] = latencyMax[type];
                }
              }

              return stats;
            } catch (e) {
              reportError('getCorrelationStats_failed', e);
              return { error: e.message || 'getCorrelationStats failed' };
            }
          },

          config: config
        };
      }
    } catch (e) {
      console.error('[DevTool][Mutation] Failed to export API:', e);
    }

  } catch (e) {
    // Top-level failure - log and abort
    console.error('[DevTool][Mutation] Module initialization failed:', e);
  }
})();
