(
    args = {
      doHighlightElements: true,
      focusHighlightIndex: -1,
      viewportExpansion: 0,
      debugMode: false,
      recordingData: {},
      elementsConfig: []
    }
  ) => {
    const { doHighlightElements, focusHighlightIndex, viewportExpansion, debugMode } = args;
    let highlightIndex = 0; // Reset highlight index
    let recordingData = args.recordingData || {};
    let elementsConfig = args.elementsConfig || [];
    let steps = args.recordingData?.processedSteps || [];


    // Add timing stack to handle recursion
    const TIMING_STACK = {
      nodeProcessing: [],
      treeTraversal: [],
      highlighting: [],
      current: null
    };
  
    function pushTiming(type) {
      TIMING_STACK[type] = TIMING_STACK[type] || [];
      TIMING_STACK[type].push(performance.now());
    }
  
    function popTiming(type) {
      const start = TIMING_STACK[type].pop();
      const duration = performance.now() - start;
      return duration;
    }
  
    // Only initialize performance tracking if in debug mode
    const PERF_METRICS = debugMode ? {
      buildDomTreeCalls: 0,
      timings: {
        buildDomTree: 0,
        highlightElement: 0,
        isInteractiveElement: 0,
        isElementVisible: 0,
        isTopElement: 0,
        isInExpandedViewport: 0,
        isTextNodeVisible: 0,
        getEffectiveScroll: 0,
      },
      cacheMetrics: {
        boundingRectCacheHits: 0,
        boundingRectCacheMisses: 0,
        computedStyleCacheHits: 0,
        computedStyleCacheMisses: 0,
        getBoundingClientRectTime: 0,
        getComputedStyleTime: 0,
        boundingRectHitRate: 0,
        computedStyleHitRate: 0,
        overallHitRate: 0,
        clientRectsCacheHits: 0,
        clientRectsCacheMisses: 0,
      },
      nodeMetrics: {
        totalNodes: 0,
        processedNodes: 0,
        skippedNodes: 0,
      },
      buildDomTreeBreakdown: {
        totalTime: 0,
        totalSelfTime: 0,
        buildDomTreeCalls: 0,
        domOperations: {
          getBoundingClientRect: 0,
          getComputedStyle: 0,
        },
        domOperationCounts: {
          getBoundingClientRect: 0,
          getComputedStyle: 0,
        }
      }
    } : null;
  
    // Simple timing helper that only runs in debug mode
    function measureTime(fn) {
      if (!debugMode) return fn;
      return function (...args) {
        const start = performance.now();
        const result = fn.apply(this, args);
        const duration = performance.now() - start;
        return result;
      };
    }
  
    // Helper to measure DOM operations
    function measureDomOperation(operation, name) {
      if (!debugMode) return operation();
  
      const start = performance.now();
      const result = operation();
      const duration = performance.now() - start;
  
      if (PERF_METRICS && name in PERF_METRICS.buildDomTreeBreakdown.domOperations) {
        PERF_METRICS.buildDomTreeBreakdown.domOperations[name] += duration;
        PERF_METRICS.buildDomTreeBreakdown.domOperationCounts[name]++;
      }
  
      return result;
    }
  
    // Add caching mechanisms at the top level
    const DOM_CACHE = {
      boundingRects: new WeakMap(),
      clientRects: new WeakMap(),
      computedStyles: new WeakMap(),
      clearCache: () => {
        DOM_CACHE.boundingRects = new WeakMap();
        DOM_CACHE.clientRects = new WeakMap();
        DOM_CACHE.computedStyles = new WeakMap();
      }
    };
  
    // Cache helper functions
    function getCachedBoundingRect(element) {
      if (!element) return null;
  
      if (DOM_CACHE.boundingRects.has(element)) {
        if (debugMode && PERF_METRICS) {
          PERF_METRICS.cacheMetrics.boundingRectCacheHits++;
        }
        return DOM_CACHE.boundingRects.get(element);
      }
  
      if (debugMode && PERF_METRICS) {
        PERF_METRICS.cacheMetrics.boundingRectCacheMisses++;
      }
  
      let rect;
      if (debugMode) {
        const start = performance.now();
        rect = element.getBoundingClientRect();
        const duration = performance.now() - start;
        if (PERF_METRICS) {
          PERF_METRICS.buildDomTreeBreakdown.domOperations.getBoundingClientRect += duration;
          PERF_METRICS.buildDomTreeBreakdown.domOperationCounts.getBoundingClientRect++;
        }
      } else {
        rect = element.getBoundingClientRect();
      }
  
      if (rect) {
        DOM_CACHE.boundingRects.set(element, rect);
      }
      return rect;
    }
  
    function getCachedComputedStyle(element) {
      if (!element) return null;
  
      if (DOM_CACHE.computedStyles.has(element)) {
        if (debugMode && PERF_METRICS) {
          PERF_METRICS.cacheMetrics.computedStyleCacheHits++;
        }
        return DOM_CACHE.computedStyles.get(element);
      }
  
      if (debugMode && PERF_METRICS) {
        PERF_METRICS.cacheMetrics.computedStyleCacheMisses++;
      }
  
      let style;
      if (debugMode) {
        const start = performance.now();
        style = window.getComputedStyle(element);
        const duration = performance.now() - start;
        if (PERF_METRICS) {
          PERF_METRICS.buildDomTreeBreakdown.domOperations.getComputedStyle += duration;
          PERF_METRICS.buildDomTreeBreakdown.domOperationCounts.getComputedStyle++;
        }
      } else {
        style = window.getComputedStyle(element);
      }
  
      if (style) {
        DOM_CACHE.computedStyles.set(element, style);
      }
      return style;
    }
  
    // Add a new function to get cached client rects
    function getCachedClientRects(element) {
      if (!element) return null;
      
      if (DOM_CACHE.clientRects.has(element)) {
        if (debugMode && PERF_METRICS) {
          PERF_METRICS.cacheMetrics.clientRectsCacheHits++;
        }
        return DOM_CACHE.clientRects.get(element);
      }
      
      if (debugMode && PERF_METRICS) {
        PERF_METRICS.cacheMetrics.clientRectsCacheMisses++;
      }
      
      const rects = element.getClientRects();
      
      if (rects) {
        DOM_CACHE.clientRects.set(element, rects);
      }
      return rects;
    }
  
    /**
     * Hash map of DOM nodes indexed by their highlight index.
     *
     * @type {Object<string, any>}
     */
    const DOM_HASH_MAP = {};
  
    const ID = { current: 0 };
  
    const HIGHLIGHT_CONTAINER_ID = "playwright-highlight-container";
  
    // Add a WeakMap cache for XPath strings
    const xpathCache = new WeakMap();
  
    // Initialize once and reuse
    const viewportObserver = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          elementVisibilityMap.set(entry.target, entry.isIntersecting);
        });
      },
      { rootMargin: `${viewportExpansion}px` }
    );
  
    /**
     * Highlights an element in the DOM and returns the index of the next element.
     */
    function highlightElement(element, index, parentIframe = null) {
      pushTiming('highlighting');
      
      if (!element) return index;
  
      // Store overlays and the single label for updating
      const overlays = [];
      let label = null;
      let labelWidth = 20;
      let labelHeight = 16;
      let cleanupFn = null;
  
      try {
        // Create or get highlight container
        let container = document.getElementById(HIGHLIGHT_CONTAINER_ID);
        if (!container) {
          container = document.createElement("div");
          container.id = HIGHLIGHT_CONTAINER_ID;
          container.style.position = "fixed";
          container.style.pointerEvents = "none";
          container.style.top = "0";
          container.style.left = "0";
          container.style.width = "100%";
          container.style.height = "100%";
          container.style.zIndex = "2147483640";
          container.style.backgroundColor = 'transparent';
          document.body.appendChild(container);
        }
  
        // Get element client rects
        const rects = element.getClientRects(); // Use getClientRects()
  
        if (!rects || rects.length === 0) return index; // Exit if no rects
  
        // Generate a color based on the index
        const colors = [
          "#FF0000",
          "#00FF00",
          "#0000FF",
          "#FFA500",
          "#800080",
          "#008080",
          "#FF69B4",
          "#4B0082",
          "#FF4500",
          "#2E8B57",
          "#DC143C",
          "#4682B4",
        ];
        const colorIndex = index % colors.length;
        const baseColor = colors[colorIndex];
        const backgroundColor = baseColor + "1A"; // 10% opacity version of the color
  
        // Get iframe offset if necessary
        let iframeOffset = { x: 0, y: 0 };
        if (parentIframe) {
          const iframeRect = parentIframe.getBoundingClientRect(); // Keep getBoundingClientRect for iframe offset
          iframeOffset.x = iframeRect.left;
          iframeOffset.y = iframeRect.top;
        }
  
        // Create fragment to hold overlay elements
        const fragment = document.createDocumentFragment();
  
        // Create highlight overlays for each client rect
        for (const rect of rects) {
          if (rect.width === 0 || rect.height === 0) continue; // Skip empty rects
  
          const overlay = document.createElement("div");
          overlay.style.position = "fixed";
          overlay.style.border = `2px solid ${baseColor}`;
          overlay.style.backgroundColor = backgroundColor;
          overlay.style.pointerEvents = "none";
          overlay.style.boxSizing = "border-box";
  
          const top = rect.top + iframeOffset.y;
          const left = rect.left + iframeOffset.x;
  
          overlay.style.top = `${top}px`;
          overlay.style.left = `${left}px`;
          overlay.style.width = `${rect.width}px`;
          overlay.style.height = `${rect.height}px`;
  
          fragment.appendChild(overlay);
          overlays.push({ element: overlay, initialRect: rect }); // Store overlay and its rect
        }
  
        // Create and position a single label relative to the first rect
        const firstRect = rects[0];
        label = document.createElement("div");
        label.className = "playwright-highlight-label";
        label.style.position = "fixed";
        label.style.background = baseColor;
        label.style.color = "white";
        label.style.padding = "1px 4px";
        label.style.borderRadius = "4px";
        label.style.fontSize = `${Math.min(12, Math.max(8, firstRect.height / 2))}px`;
        label.textContent = index;
  
        labelWidth = label.offsetWidth > 0 ? label.offsetWidth : labelWidth; // Update actual width if possible
        labelHeight = label.offsetHeight > 0 ? label.offsetHeight : labelHeight; // Update actual height if possible
  
        const firstRectTop = firstRect.top + iframeOffset.y;
        const firstRectLeft = firstRect.left + iframeOffset.x;
  
        let labelTop = firstRectTop + 2;
        let labelLeft = firstRectLeft + firstRect.width - labelWidth - 2;
  
        // Adjust label position if first rect is too small
        if (firstRect.width < labelWidth + 4 || firstRect.height < labelHeight + 4) {
          labelTop = firstRectTop - labelHeight - 2;
          labelLeft = firstRectLeft + firstRect.width - labelWidth; // Align with right edge
          if (labelLeft < iframeOffset.x) labelLeft = firstRectLeft; // Prevent going off-left
        }
  
        // Ensure label stays within viewport bounds slightly better
        labelTop = Math.max(0, Math.min(labelTop, window.innerHeight - labelHeight));
        labelLeft = Math.max(0, Math.min(labelLeft, window.innerWidth - labelWidth));
  
  
        label.style.top = `${labelTop}px`;
        label.style.left = `${labelLeft}px`;
  
        fragment.appendChild(label);
  
        // Update positions on scroll/resize
        const updatePositions = () => {
          const newRects = element.getClientRects(); // Get fresh rects
          let newIframeOffset = { x: 0, y: 0 };
  
          if (parentIframe) {
            const iframeRect = parentIframe.getBoundingClientRect(); // Keep getBoundingClientRect for iframe
            newIframeOffset.x = iframeRect.left;
            newIframeOffset.y = iframeRect.top;
          }
  
          // Update each overlay
          overlays.forEach((overlayData, i) => {
            if (i < newRects.length) { // Check if rect still exists
              const newRect = newRects[i];
              const newTop = newRect.top + newIframeOffset.y;
              const newLeft = newRect.left + newIframeOffset.x;
  
              overlayData.element.style.top = `${newTop}px`;
              overlayData.element.style.left = `${newLeft}px`;
              overlayData.element.style.width = `${newRect.width}px`;
              overlayData.element.style.height = `${newRect.height}px`;
              overlayData.element.style.display = (newRect.width === 0 || newRect.height === 0) ? 'none' : 'block';
            } else {
              // If fewer rects now, hide extra overlays
              overlayData.element.style.display = 'none';
            }
          });
  
          // If there are fewer new rects than overlays, hide the extras
          if (newRects.length < overlays.length) {
            for (let i = newRects.length; i < overlays.length; i++) {
              overlays[i].element.style.display = 'none';
            }
          }
  
          // Update label position based on the first new rect
          if (label && newRects.length > 0) {
            const firstNewRect = newRects[0];
            const firstNewRectTop = firstNewRect.top + newIframeOffset.y;
            const firstNewRectLeft = firstNewRect.left + newIframeOffset.x;
  
            let newLabelTop = firstNewRectTop + 2;
            let newLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth - 2;
  
            if (firstNewRect.width < labelWidth + 4 || firstNewRect.height < labelHeight + 4) {
              newLabelTop = firstNewRectTop - labelHeight - 2;
              newLabelLeft = firstNewRectLeft + firstNewRect.width - labelWidth;
              if (newLabelLeft < newIframeOffset.x) newLabelLeft = firstNewRectLeft;
            }
  
            // Ensure label stays within viewport bounds
            newLabelTop = Math.max(0, Math.min(newLabelTop, window.innerHeight - labelHeight));
            newLabelLeft = Math.max(0, Math.min(newLabelLeft, window.innerWidth - labelWidth));
  
            label.style.top = `${newLabelTop}px`;
            label.style.left = `${newLabelLeft}px`;
            label.style.display = 'block';
          } else if (label) {
            // Hide label if element has no rects anymore
            label.style.display = 'none';
          }
        };
  
        const throttleFunction = (func, delay) => {
          let lastCall = 0;
          return (...args) => {
            const now = performance.now();
            if (now - lastCall < delay) return;
            lastCall = now;
            return func(...args);
          };
        };
  
        const throttledUpdatePositions = throttleFunction(updatePositions, 16); // ~60fps
        window.addEventListener('scroll', throttledUpdatePositions, true);
        window.addEventListener('resize', throttledUpdatePositions);
        
        // Add cleanup function
        cleanupFn = () => {
          window.removeEventListener('scroll', throttledUpdatePositions, true);
          window.removeEventListener('resize', throttledUpdatePositions);
          // Remove overlay elements if needed
          overlays.forEach(overlay => overlay.element.remove());
          if (label) label.remove();
        };
        
        // Then add fragment to container in one operation
        container.appendChild(fragment);
        
        return index + 1;
      } finally {
        popTiming('highlighting');
        // Store cleanup function for later use
        if (cleanupFn) {
          // Keep a reference to cleanup functions in a global array
          (window._highlightCleanupFunctions = window._highlightCleanupFunctions || []).push(cleanupFn);
        }
      }
    }
  
    // Add this function to perform cleanup when needed
    function cleanupHighlights() {
      if (window._highlightCleanupFunctions && window._highlightCleanupFunctions.length) {
        window._highlightCleanupFunctions.forEach(fn => fn());
        window._highlightCleanupFunctions = [];
      }
      
      // Also remove the container
      const container = document.getElementById(HIGHLIGHT_CONTAINER_ID);
      if (container) container.remove();
    }
  
    function getElementPosition(currentElement) {
      if (!currentElement.parentElement) {
        return 0; // No parent means no siblings
      }
    
      const tagName = currentElement.nodeName.toLowerCase();
    
      const siblings = Array.from(currentElement.parentElement.children)
        .filter((sib) => sib.nodeName.toLowerCase() === tagName);
    
      if (siblings.length === 1) {
        return 0; // Only element of its type
      }
    
      const index = siblings.indexOf(currentElement) + 1; // 1-based index
      return index;
    }
  
    /**
     * Returns an XPath tree string for an element.
     */
    function getXPathTree(element, stopAtBoundary = true) {
      if (xpathCache.has(element)) return xpathCache.get(element);
      
      const segments = [];
      let currentElement = element;
  
      while (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) {
        // Stop if we hit a shadow root or iframe
        if (
          stopAtBoundary &&
          (currentElement.parentNode instanceof ShadowRoot ||
            currentElement.parentNode instanceof HTMLIFrameElement)
        ) {
          break;
        }
  
        const position = getElementPosition(currentElement);
        const tagName = currentElement.nodeName.toLowerCase();
        const xpathIndex = position > 0 ? `[${position}]` : "";
        segments.unshift(`${tagName}${xpathIndex}`);
  
        currentElement = currentElement.parentNode;
      }
  
      const result = segments.join("/");
      xpathCache.set(element, result);
      return result;
    }
  
    /**
     * Checks if a text node is visible.
     */
    function isTextNodeVisible(textNode) {
      try {
        // Special case: when viewportExpansion is -1, consider all text nodes as visible
        if (viewportExpansion === -1) {
          // Still check parent visibility for basic filtering
          const parentElement = textNode.parentElement;
          if (!parentElement) return false;
  
          try {
            return parentElement.checkVisibility({
              checkOpacity: true,
              checkVisibilityCSS: true,
            });
          } catch (e) {
            // Fallback if checkVisibility is not supported
            const style = window.getComputedStyle(parentElement);
            return style.display !== 'none' &&
              style.visibility !== 'hidden' &&
              style.opacity !== '0';
          }
        }
        
        const range = document.createRange();
        range.selectNodeContents(textNode);
        const rects = range.getClientRects(); // Use getClientRects for Range
  
        if (!rects || rects.length === 0) {
          return false;
        }
  
        let isAnyRectVisible = false;
        let isAnyRectInViewport = false;
  
        for (const rect of rects) {
          // Check size
          if (rect.width > 0 && rect.height > 0) {
            isAnyRectVisible = true;
  
            // Viewport check for this rect
            if (!(
              rect.bottom < -viewportExpansion ||
              rect.top > window.innerHeight + viewportExpansion ||
              rect.right < -viewportExpansion ||
              rect.left > window.innerWidth + viewportExpansion
            )) {
              isAnyRectInViewport = true;
              break; // Found a visible rect in viewport, no need to check others
            }
          }
        }
  
        if (!isAnyRectVisible || !isAnyRectInViewport) {
          return false;
        }
  
        // Check parent visibility
        const parentElement = textNode.parentElement;
        if (!parentElement) return false;
  
        try {
          return parentElement.checkVisibility({
            checkOpacity: true,
            checkVisibilityCSS: true,
          });
        } catch (e) {
          // Fallback if checkVisibility is not supported
          const style = window.getComputedStyle(parentElement);
          return style.display !== 'none' &&
            style.visibility !== 'hidden' &&
            style.opacity !== '0';
        }
      } catch (e) {
        console.warn('Error checking text node visibility:', e);
        return false;
      }
    }
  
    // Helper function to check if element is accepted
    function isElementAccepted(element) {
      if (!element || !element.tagName) return false;
  
      // Always accept body and common container elements
      const alwaysAccept = new Set([
        "body", "div", "main", "article", "section", "nav", "header", "footer"
      ]);
      const tagName = element.tagName.toLowerCase();
  
      if (alwaysAccept.has(tagName)) return true;
  
      const leafElementDenyList = new Set([
        "svg",
        "script",
        "style",
        "link",
        "meta",
        "noscript",
        "template",
      ]);
  
      return !leafElementDenyList.has(tagName);
    }
  
    /**
     * Checks if an element is visible.
     */
    function isElementVisible(element) {
      const style = getCachedComputedStyle(element);
      return (
        element.offsetWidth > 0 &&
        element.offsetHeight > 0 &&
        style.visibility !== "hidden" &&
        style.display !== "none"
      );
    }


    const isScrollableElement = (element) => {
        if (!element || element.nodeType !== 1) return false;
        const style = window.getComputedStyle(element);
        const overflowY = style.overflowY;
        const overflowX = style.overflowX;
        const isOverflowY = ['auto', 'scroll', 'overlay'].includes(overflowY);
        const isOverflowX = ['auto', 'scroll', 'overlay'].includes(overflowX);
        const canScrollY = element.scrollHeight > element.clientHeight;
        const canScrollX = element.scrollWidth > element.clientWidth;
        return (isOverflowY && canScrollY) || (isOverflowX && canScrollX);
      };
  
    /**
     * Checks if an element is interactive.
     * 
     * lots of comments, and uncommented code - to show the logic of what we already tried
     * 
     * One of the things we tried at the beginning was also to use event listeners, and other fancy class, style stuff -> what actually worked best was just combining most things with computed cursor style :)
     */
    function isInteractiveElement(element) {
      if (!element || element.nodeType !== Node.ELEMENT_NODE) {
        return false;
      }
      
        const steps = recordingData.processedSteps || [];

        const config = elementsConfig.find(config => window.location.href.includes(config.domain))

        if(config) {
            const elementConfig = config.elements.find(el => {
                const isMatchClassName = element.className && el.className?.includes?.(element.className);
                const isMatchId = element.id && el.id && element.id === el.id
                return isMatchClassName || isMatchId
            })

            if(elementConfig) {
                console.log(elementConfig,element, 'elementConfig')
                return {
                    type: elementConfig.type,
                    desc: elementConfig.desc
                }
            }
        }


        if (steps.length > 0 && element.nodeType === Node.ELEMENT_NODE) {
            const step = steps.find(step => {
                const eventInfo = step.eventInfo || {}
                const stepNodeId = eventInfo.id || eventInfo.target?.attributes?.id
                const stepNodeClassName = (eventInfo.className || eventInfo.target?.attributes?.class || '')?.split(' ')
                const stepNodeTagName = eventInfo.tagName || eventInfo.target?.tagName || ''
                const isMatchURL = (step.url || '').includes(window.location.origin);
                const isMatchTagName = stepNodeTagName.toLowerCase() === element.tagName.toLowerCase();
                const isMatchId = stepNodeId && element.id && stepNodeId === element.id
                const elementClassList = [...element.classList]
                const isMatchClassName = stepNodeClassName && element.className && stepNodeClassName?.length === elementClassList?.length && stepNodeClassName?.every(v => elementClassList?.includes?.(v))
                
                const dataAttribute = element.dataset
                const elementDataAttributeKeys = Object.keys(dataAttribute).map(v => `data-${v}`) || []
                const stepDataAttributeKeys = Object.keys(eventInfo?.dom?.attributes || {}).filter(v => v.startsWith('data-')) || []


                const domSelector = eventInfo?.domSelector && document.querySelector(eventInfo?.domSelector)
                
                const isMatchDomSelector = domSelector && domSelector === element

                // if(eventInfo.tagName === 'use') {
                //     console.log(element, elementDataAttributeKeys, stepDataAttributeKeys, 'elementDataAttributeKeys, stepDataAttributeKeys')
                // }

                // if(isMatchClassName) {
                //   console.log(element, step,element.className, element.classList,isMatchTagName, isMatchURL && isMatchTagName && (isMatchId || isMatchClassName) ,'isMatchClassName')
                // }
                
                const isMatchDataAttribute = stepDataAttributeKeys.length === elementDataAttributeKeys.length && stepDataAttributeKeys.every(v => elementDataAttributeKeys.includes(v))

                // if(eventInfo?.domSelector && isMatchDomSelector) {
                //   return
                // }
                if(isMatchDomSelector) {
                  return true
                }
                // if (isMatchURL && isMatchTagName && (isMatchId || isMatchClassName) && element.style.display !== 'none') {
                //     console.log('recording', step)
                //     return true;
                // }
                return false;
            });
            if (step) {
                const desc = JSON.stringify(step.domOperationInfo)
                return {
                    type: step.event,
                    desc: desc ? `Element Comment: ${desc}` : undefined,
                };
            }
        }

        // if(isScrollableElement(element)) {
        //     return {
        //         type: 'scroll',
        //         desc: 'Scrollable Element',
        //     }
        // }
      // Cache the tagName and style lookups
      const tagName = element.tagName.toLowerCase();
      const style = getCachedComputedStyle(element);
  
      // Define interactive cursors
      const interactiveCursors = new Set([
        'pointer',    // Link/clickable elements
        'move',       // Movable elements
        'text',       // Text selection
        'grab',       // Grabbable elements
        'grabbing',   // Currently grabbing
        'cell',       // Table cell selection
        'copy',       // Copy operation
        'alias',      // Alias creation
        'all-scroll', // Scrollable content
        'col-resize', // Column resize
        'context-menu', // Context menu available
        'crosshair',  // Precise selection
        'e-resize',   // East resize
        'ew-resize',  // East-west resize
        'help',       // Help available
        'n-resize',   // North resize
        'ne-resize',  // Northeast resize
        'nesw-resize', // Northeast-southwest resize
        'ns-resize',  // North-south resize
        'nw-resize',  // Northwest resize
        'nwse-resize', // Northwest-southeast resize
        'row-resize', // Row resize
        's-resize',   // South resize
        'se-resize',  // Southeast resize
        'sw-resize',  // Southwest resize
        'vertical-text', // Vertical text selection
        'w-resize',   // West resize
        'zoom-in',    // Zoom in
        'zoom-out'    // Zoom out
      ]);
  
      // Define non-interactive cursors
      const nonInteractiveCursors = new Set([
        'not-allowed', // Action not allowed
        'no-drop',     // Drop not allowed
        'wait',        // Processing
        'progress',    // In progress
        'initial',     // Initial value
        'inherit'      // Inherited value
        //? Let's just include all potentially clickable elements that are not specifically blocked
        // 'none',        // No cursor
        // 'default',     // Default cursor 
        // 'auto',        // Browser default
      ]);
  
      function doesElementHaveInteractivePointer(element) {
        if (element.tagName.toLowerCase() === "html") return false;
  
        if (interactiveCursors.has(style.cursor)) return true;
  
        return false;
      }
  
      let isInteractiveCursor = doesElementHaveInteractivePointer(element);
  
      // Genius fix for almost all interactive elements
      if (isInteractiveCursor) {
        return true;
      }


      
  
      const interactiveElements = new Set([
        "a",          // Links
        "button",     // Buttons
        "input",      // All input types (text, checkbox, radio, etc.)
        "select",     // Dropdown menus
        "textarea",   // Text areas
        "details",    // Expandable details
        "summary",    // Summary element (clickable part of details)
        "label",      // Form labels (often clickable)
        "option",     // Select options
        "optgroup",   // Option groups
        "fieldset",   // Form fieldsets (can be interactive with legend)
        "legend",     // Fieldset legends
      ]);
  
      // Define explicit disable attributes and properties
      const explicitDisableTags = new Set([
        'disabled',           // Standard disabled attribute
        // 'aria-disabled',      // ARIA disabled state
        'readonly',          // Read-only state
        // 'aria-readonly',     // ARIA read-only state
        // 'aria-hidden',       // Hidden from accessibility
        // 'hidden',            // Hidden attribute
        // 'inert',             // Inert attribute
        // 'aria-inert',        // ARIA inert state
        // 'tabindex="-1"',     // Removed from tab order
        // 'aria-hidden="true"' // Hidden from screen readers
      ]);
  
      // handle inputs, select, checkbox, radio, textarea, button and make sure they are not cursor style disabled/not-allowed
      if (interactiveElements.has(tagName)) {
        // Check for non-interactive cursor
        if (nonInteractiveCursors.has(style.cursor)) {
          return false;
        }
  
        // Check for explicit disable attributes
        for (const disableTag of explicitDisableTags) {
          if (element.hasAttribute(disableTag) ||
            element.getAttribute(disableTag) === 'true' ||
            element.getAttribute(disableTag) === '') {
            return false;
          }
        }
  
        // Check for disabled property on form elements
        if (element.disabled) {
          return false;
        }
  
        // Check for readonly property on form elements
        if (element.readOnly) {
          return false;
        }
  
        // Check for inert property
        if (element.inert) {
          return false;
        }
  
        return true;
      }
  
      const role = element.getAttribute("role");
      const ariaRole = element.getAttribute("aria-role");
  
      // Check for contenteditable attribute
      if (element.getAttribute("contenteditable") === "true" || element.isContentEditable) {
        return true;
      }
      
      // Added enhancement to capture dropdown interactive elements
      if (element.classList && (
        element.classList.contains("button") ||
        element.classList.contains('dropdown-toggle') ||
        element.getAttribute('data-index') ||
        element.getAttribute('data-toggle') === 'dropdown' ||
        element.getAttribute('aria-haspopup') === 'true'
      )) {
        return true;
      }
  
      const interactiveRoles = new Set([
        'button',           // Directly clickable element
        // 'link',            // Clickable link
        // 'menuitem',        // Clickable menu item
        'menuitemradio',   // Radio-style menu item (selectable)
        'menuitemcheckbox', // Checkbox-style menu item (toggleable)
        'radio',           // Radio button (selectable)
        'checkbox',        // Checkbox (toggleable)
        'tab',             // Tab (clickable to switch content)
        'switch',          // Toggle switch (clickable to change state)
        'slider',          // Slider control (draggable)
        'spinbutton',      // Number input with up/down controls
        'combobox',        // Dropdown with text input
        'searchbox',       // Search input field
        'textbox',         // Text input field
        // 'listbox',         // Selectable list
        'option',          // Selectable option in a list
        'scrollbar'        // Scrollable control
      ]);
  
      // Basic role/attribute checks
      const hasInteractiveRole =
        interactiveElements.has(tagName) ||
        interactiveRoles.has(role) ||
        interactiveRoles.has(ariaRole);
  
      if (hasInteractiveRole) return true;
  
      // check whether element has event listeners
      try {
        if (typeof getEventListeners === 'function') {
          const listeners = getEventListeners(element);
          const mouseEvents = ['click', 'mousedown', 'mouseup', 'dblclick'];
          for (const eventType of mouseEvents) {
            if (listeners[eventType] && listeners[eventType].length > 0) {
              return true; // Found a mouse interaction listener
            }
          }
        } else {
          // Fallback: Check common event attributes if getEventListeners is not available
          const commonMouseAttrs = ['onclick', 'onmousedown', 'onmouseup', 'ondblclick'];
          if (commonMouseAttrs.some(attr => element.hasAttribute(attr))) {
            return true;
          }
        }
      } catch (e) {
        // console.warn(`Could not check event listeners for ${element.tagName}:`, e);
        // If checking listeners fails, rely on other checks
      }
  
      return false
    }
  
  
    /**
     * Checks if an element is the topmost element at its position.
     */
    function isTopElement(element) {
      // Special case: when viewportExpansion is -1, consider all elements as "top" elements
      if (viewportExpansion === -1) {
        return true;
      }
      
      const rects = getCachedClientRects(element); // Replace element.getClientRects()
  
      if (!rects || rects.length === 0) {
        return false; // No geometry, cannot be top
      }
  
      let isAnyRectInViewport = false;
      for (const rect of rects) {
        // Use the same logic as isInExpandedViewport check
        if (rect.width > 0 && rect.height > 0 && !( // Only check non-empty rects
          rect.bottom < -viewportExpansion ||
          rect.top > window.innerHeight + viewportExpansion ||
          rect.right < -viewportExpansion ||
          rect.left > window.innerWidth + viewportExpansion
        )) {
          isAnyRectInViewport = true;
          break;
        }
      }
  
      if (!isAnyRectInViewport) {
        return false; // All rects are outside the viewport area
      }
  
  
      // Find the correct document context and root element
      let doc = element.ownerDocument;
  
      // If we're in an iframe, elements are considered top by default
      if (doc !== window.document) {
        return true;
      }
  
      // For shadow DOM, we need to check within its own root context
      const shadowRoot = element.getRootNode();
      if (shadowRoot instanceof ShadowRoot) {
        const centerX = rects[Math.floor(rects.length / 2)].left + rects[Math.floor(rects.length / 2)].width / 2;
        const centerY = rects[Math.floor(rects.length / 2)].top + rects[Math.floor(rects.length / 2)].height / 2;
  
        try {
          const topEl = measureDomOperation(
            () => shadowRoot.elementFromPoint(centerX, centerY),
            'elementFromPoint'
          );
          if (!topEl) return false;
  
          let current = topEl;
          while (current && current !== shadowRoot) {
            if (current === element) return true;
            current = current.parentElement;
          }
          return false;
        } catch (e) {
          return true;
        }
      }
  
      // For elements in viewport, check if they're topmost
      const centerX = rects[Math.floor(rects.length / 2)].left + rects[Math.floor(rects.length / 2)].width / 2;
      const centerY = rects[Math.floor(rects.length / 2)].top + rects[Math.floor(rects.length / 2)].height / 2;
  
      try {
        const topEl = document.elementFromPoint(centerX, centerY);
        if (!topEl) return false;
  
        let current = topEl;
        while (current && current !== document.documentElement) {
          if (current === element) return true;
          current = current.parentElement;
        }
        return false;
      } catch (e) {
        return true;
      }
    }
  
    /**
     * Checks if an element is within the expanded viewport.
     */
    function isInExpandedViewport(element, viewportExpansion) {
      if (viewportExpansion === -1) {
        return true;
      }
  
      const rects = element.getClientRects(); // Use getClientRects
  
      if (!rects || rects.length === 0) {
        // Fallback to getBoundingClientRect if getClientRects is empty,
        // useful for elements like <svg> that might not have client rects but have a bounding box.
        const boundingRect = getCachedBoundingRect(element);
        if (!boundingRect || boundingRect.width === 0 || boundingRect.height === 0) {
          return false;
        }
        return !(
          boundingRect.bottom < -viewportExpansion ||
          boundingRect.top > window.innerHeight + viewportExpansion ||
          boundingRect.right < -viewportExpansion ||
          boundingRect.left > window.innerWidth + viewportExpansion
        );
      }
  
      // Check if *any* client rect is within the viewport
      for (const rect of rects) {
        if (rect.width === 0 || rect.height === 0) continue; // Skip empty rects
  
        if (!(
          rect.bottom < -viewportExpansion ||
          rect.top > window.innerHeight + viewportExpansion ||
          rect.right < -viewportExpansion ||
          rect.left > window.innerWidth + viewportExpansion
        )) {
          return true; // Found at least one rect in the viewport
        }
      }
  
      return false; // No rects were found in the viewport
    }
  
    // Add this new helper function
    function getEffectiveScroll(element) {
      let currentEl = element;
      let scrollX = 0;
      let scrollY = 0;
  
      return measureDomOperation(() => {
        while (currentEl && currentEl !== document.documentElement) {
          if (currentEl.scrollLeft || currentEl.scrollTop) {
            scrollX += currentEl.scrollLeft;
            scrollY += currentEl.scrollTop;
          }
          currentEl = currentEl.parentElement;
        }
  
        scrollX += window.scrollX;
        scrollY += window.scrollY;
  
        return { scrollX, scrollY };
      }, 'scrollOperations');
    }
  
    // Add these helper functions at the top level
    function isInteractiveCandidate(element) {
      if (!element || element.nodeType !== Node.ELEMENT_NODE) return false;
  
      const tagName = element.tagName.toLowerCase();
  
      // Fast-path for common interactive elements
      const interactiveElements = new Set([
        "a", "button", "input", "select", "textarea", "details", "summary"
      ]);
  
      if (interactiveElements.has(tagName)) return true;
  
      // Quick attribute checks without getting full lists
      const hasQuickInteractiveAttr = element.hasAttribute("onclick") ||
        element.hasAttribute("role") ||
        element.hasAttribute("tabindex") ||
        element.hasAttribute("aria-") ||
        element.hasAttribute("data-action") ||
        element.getAttribute("contenteditable") === "true";
  
      return hasQuickInteractiveAttr;
    }
  
    // --- Define constants for distinct interaction check ---
    const DISTINCT_INTERACTIVE_TAGS = new Set([
      'a', 'button', 'input', 'select', 'textarea', 'summary', 'details', 'label', 'option'
    ]);
    const INTERACTIVE_ROLES = new Set([
      'button', 'link', 'menuitem', 'menuitemradio', 'menuitemcheckbox',
      'radio', 'checkbox', 'tab', 'switch', 'slider', 'spinbutton',
      'combobox', 'searchbox', 'textbox', 'listbox', 'option', 'scrollbar'
    ]);
  
    /**
     * Checks if an element likely represents a distinct interaction
     * separate from its parent (if the parent is also interactive).
     */
    function isElementDistinctInteraction(element) {
      if (!element || element.nodeType !== Node.ELEMENT_NODE) {
        return false;
      }
  
      const tagName = element.tagName.toLowerCase();
      const role = element.getAttribute('role');
  
      // Check if it's an iframe - always distinct boundary
      if (tagName === 'iframe') {
        return true;
      }
  
      // Check tag name
      if (DISTINCT_INTERACTIVE_TAGS.has(tagName)) {
        return true;
      }
      // Check interactive roles
      if (role && INTERACTIVE_ROLES.has(role)) {
        return true;
      }
      // Check contenteditable
      if (element.isContentEditable || element.getAttribute('contenteditable') === 'true') {
        return true;
      }
      // Check for common testing/automation attributes
      if (element.hasAttribute('data-testid') || element.hasAttribute('data-cy') || element.hasAttribute('data-test')) {
        return true;
      }
      // Check for explicit onclick handler (attribute or property)
      if (element.hasAttribute('onclick') || typeof element.onclick === 'function') {
        return true;
      }
      // Check for other common interaction event listeners
      try {
        const getEventListeners = window.getEventListenersForNode;
        if (typeof getEventListeners === 'function') {
          const listeners = getEventListeners(element);
          const interactionEvents = ['mousedown', 'mouseup', 'keydown', 'keyup', 'submit', 'change', 'input', 'focus', 'blur'];
          for (const eventType of interactionEvents) {
            if (listeners[eventType] && listeners[eventType].length > 0) {
              return true; // Found a common interaction listener
            }
          }
        } else {
          // Fallback: Check common event attributes if getEventListeners is not available
          const commonEventAttrs = ['onmousedown', 'onmouseup', 'onkeydown', 'onkeyup', 'onsubmit', 'onchange', 'oninput', 'onfocus', 'onblur'];
          if (commonEventAttrs.some(attr => element.hasAttribute(attr))) {
            return true;
          }
        }
      } catch (e) {
        // console.warn(`Could not check event listeners for ${element.tagName}:`, e);
        // If checking listeners fails, rely on other checks
      }
  
  
      // Default to false: if it's interactive but doesn't match above,
      // assume it triggers the same action as the parent.
      return false;
    }
    // --- End distinct interaction check ---
  
    /**
     * Handles the logic for deciding whether to highlight an element and performing the highlight.
     */
    function handleHighlighting(nodeData, node, parentIframe, isParentHighlighted) {
      if (!nodeData.isInteractive) return false; // Not interactive, definitely don't highlight
      

      let shouldHighlight = false;
      if (!isParentHighlighted) {
        // Parent wasn't highlighted, this interactive node can be highlighted.
        shouldHighlight = true;
      } else {
        // Parent *was* highlighted. Only highlight this node if it represents a distinct interaction.
        if (isElementDistinctInteraction(node)) {
          shouldHighlight = true;
        } else {
          // console.log(`Skipping highlight for ${nodeData.tagName} (parent highlighted)`);
          shouldHighlight = false;
        }
      }


      if (nodeData.isRecording) {
    
        shouldHighlight = true;
      }

      if(node.classList.contains('count')) {
        console.log(nodeData, shouldHighlight, node, 'nodeData')
      }
  
      if (shouldHighlight) {
        // Check viewport status before assigning index and highlighting
        nodeData.isInViewport = isInExpandedViewport(node, viewportExpansion);
        
        // When viewportExpansion is -1, all interactive elements should get a highlight index
        // regardless of viewport status
        if (nodeData.isInViewport || viewportExpansion === -1) {
          nodeData.highlightIndex = highlightIndex++;
  
          if (doHighlightElements) {
            if (focusHighlightIndex >= 0) {
              if (focusHighlightIndex === nodeData.highlightIndex) {
                highlightElement(node, nodeData.highlightIndex, parentIframe);
              }
            } else {
              highlightElement(node, nodeData.highlightIndex, parentIframe);
            }
            return true; // Successfully highlighted
          }
        } else {
          // console.log(`Skipping highlight for ${nodeData.tagName} (outside viewport)`);
        }
      }
  
      return false; // Did not highlight
    }
  
    /**
     * Creates a node data object for a given node and its descendants.
     */
    function buildDomTree(node, parentIframe = null, isParentHighlighted = false) {
      // Fast rejection checks first
      if (!node || node.id === HIGHLIGHT_CONTAINER_ID || 
          (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE)) {
        if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
        return null;
      }
  
      if (debugMode) PERF_METRICS.nodeMetrics.totalNodes++;
  
      if (!node || node.id === HIGHLIGHT_CONTAINER_ID) {
        if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
        return null;
      }
  
      // Special handling for root node (body)
      if (node === document.body) {
        const nodeData = {
          tagName: 'body',
          attributes: {},
          xpath: '/body',
          children: [],
        };
  
        // Process children of body
        for (const child of node.childNodes) {
          const domElement = buildDomTree(child, parentIframe, false); // Body's children have no highlighted parent initially
          if (domElement) nodeData.children.push(domElement);
        }
  
        const id = `${ID.current++}`;
        DOM_HASH_MAP[id] = nodeData;
        if (debugMode) PERF_METRICS.nodeMetrics.processedNodes++;
        return id;
      }
  
      // Early bailout for non-element nodes except text
      if (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {
        if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
        return null;
      }
  
      // Process text nodes
      if (node.nodeType === Node.TEXT_NODE) {
        const textContent = node.textContent.trim();
        if (!textContent) {
          if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
          return null;
        }
  
        // Only check visibility for text nodes that might be visible
        const parentElement = node.parentElement;
        if (!parentElement || parentElement.tagName.toLowerCase() === 'script') {
          if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
          return null;
        }
  
        const id = `${ID.current++}`;
        DOM_HASH_MAP[id] = {
          type: "TEXT_NODE",
          text: textContent,
          isVisible: isTextNodeVisible(node),
        };
        if (debugMode) PERF_METRICS.nodeMetrics.processedNodes++;
        return id;
      }
  
      // Quick checks for element nodes
      if (node.nodeType === Node.ELEMENT_NODE && !isElementAccepted(node)) {
        if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
        return null;
      }
  
      // Early viewport check - only filter out elements clearly outside viewport
      if (viewportExpansion !== -1) {
        const rect = getCachedBoundingRect(node); // Keep for initial quick check
        const style = getCachedComputedStyle(node);
  
        // Skip viewport check for fixed/sticky elements as they may appear anywhere
        const isFixedOrSticky = style && (style.position === 'fixed' || style.position === 'sticky');
  
        // Check if element has actual dimensions using offsetWidth/Height (quick check)
        const hasSize = node.offsetWidth > 0 || node.offsetHeight > 0;
  
        // Use getBoundingClientRect for the quick OUTSIDE check.
        // isInExpandedViewport will do the more accurate check later if needed.
        if (!rect || (!isFixedOrSticky && !hasSize && (
          rect.bottom < -viewportExpansion ||
          rect.top > window.innerHeight + viewportExpansion ||
          rect.right < -viewportExpansion ||
          rect.left > window.innerWidth + viewportExpansion
        ))) {
          // console.log("Skipping node outside viewport (quick check):", node.tagName, rect);
          if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
          return null;
        }
      }
  
      // Process element node
      const nodeData = {
        tagName: node.tagName.toLowerCase(),
        attributes: {},
        xpath: getXPathTree(node, true),
        children: [],
      };
  
      // Get attributes for interactive elements or potential text containers
      if (isInteractiveCandidate(node) || node.tagName.toLowerCase() === 'iframe' || node.tagName.toLowerCase() === 'body') {
        const attributeNames = node.getAttributeNames?.() || [];
        for (const name of attributeNames) {
          nodeData.attributes[name] = node.getAttribute(name);
        }
      }
  
      let nodeWasHighlighted = false;
      let isScrollElement = false;
      // Perform visibility, interactivity, and highlighting checks
      if (node.nodeType === Node.ELEMENT_NODE) {
        nodeData.isVisible = isElementVisible(node); // isElementVisible uses offsetWidth/Height, which is fine
        if (nodeData.isVisible) {
          nodeData.isTopElement = isTopElement(node);
          if (nodeData.isTopElement) {
            const interactive = isInteractiveElement(node);

            isScrollElement = typeof interactive === 'object' && interactive.type?.toLowerCase?.() === 'scroll'
           
            nodeData.isInteractive = !!interactive;
            nodeData.isRecording = typeof interactive === 'object'
            nodeData.isScrollElement = isScrollElement
            const desc = interactive?.desc
            nodeData.desc = desc || undefined;
            // Call the dedicated highlighting function
            nodeWasHighlighted = handleHighlighting(nodeData, node, parentIframe, isScrollElement? false :isParentHighlighted);
          }
        }
      }
  
      // Process children, with special handling for iframes and rich text editors
      if (node.tagName) {
        const tagName = node.tagName.toLowerCase();
  
        // Handle iframes
        if (tagName === "iframe") {
          try {
            const iframeDoc = node.contentDocument || node.contentWindow?.document;
            if (iframeDoc) {
              for (const child of iframeDoc.childNodes) {
                const domElement = buildDomTree(child, node, false);
                if (domElement) nodeData.children.push(domElement);
              }
            }
          } catch (e) {
            console.warn("Unable to access iframe:", e);
          }
        }
        // Handle rich text editors and contenteditable elements
        else if (
          node.isContentEditable ||
          node.getAttribute("contenteditable") === "true" ||
          node.id === "tinymce" ||
          node.classList.contains("mce-content-body") ||
          (tagName === "body" && node.getAttribute("data-id")?.startsWith("mce_"))
        ) {
          // Process all child nodes to capture formatted text
          for (const child of node.childNodes) {
            const domElement = buildDomTree(child, parentIframe, nodeWasHighlighted);
            if (domElement) nodeData.children.push(domElement);
          }
        }
        else {
          // Handle shadow DOM
          if (node.shadowRoot) {
            nodeData.shadowRoot = true;
            for (const child of node.shadowRoot.childNodes) {
              const domElement = buildDomTree(child, parentIframe, nodeWasHighlighted);
              if (domElement) nodeData.children.push(domElement);
            }
          }
          // Handle regular elements
          for (const child of node.childNodes) {
            // Pass the highlighted status of the *current* node to its children
            const passHighlightStatusToChild = isScrollElement ? false : (nodeWasHighlighted || isParentHighlighted)
            const domElement = buildDomTree(child, parentIframe, passHighlightStatusToChild);
            if (domElement) nodeData.children.push(domElement);
          }
        }
      }
  
      // Skip empty anchor tags
      if (nodeData.tagName === 'a' && nodeData.children.length === 0 && !nodeData.attributes.href) {
        if (debugMode) PERF_METRICS.nodeMetrics.skippedNodes++;
        return null;
      }
  
      const id = `${ID.current++}`;
      DOM_HASH_MAP[id] = nodeData;
      if (debugMode) PERF_METRICS.nodeMetrics.processedNodes++;
      return id;
    }
  
    // After all functions are defined, wrap them with performance measurement
    // Remove buildDomTree from here as we measure it separately
    highlightElement = measureTime(highlightElement);
    isInteractiveElement = measureTime(isInteractiveElement);
    isElementVisible = measureTime(isElementVisible);
    isTopElement = measureTime(isTopElement);
    isInExpandedViewport = measureTime(isInExpandedViewport);
    isTextNodeVisible = measureTime(isTextNodeVisible);
    getEffectiveScroll = measureTime(getEffectiveScroll);
  
    const rootId = buildDomTree(document.body);
  
    // Clear the cache before starting
    DOM_CACHE.clearCache();
  
    // Only process metrics in debug mode
    if (debugMode && PERF_METRICS) {
      // Convert timings to seconds and add useful derived metrics
      Object.keys(PERF_METRICS.timings).forEach(key => {
        PERF_METRICS.timings[key] = PERF_METRICS.timings[key] / 1000;
      });
  
      Object.keys(PERF_METRICS.buildDomTreeBreakdown).forEach(key => {
        if (typeof PERF_METRICS.buildDomTreeBreakdown[key] === 'number') {
          PERF_METRICS.buildDomTreeBreakdown[key] = PERF_METRICS.buildDomTreeBreakdown[key] / 1000;
        }
      });
  
      // Add some useful derived metrics
      if (PERF_METRICS.buildDomTreeBreakdown.buildDomTreeCalls > 0) {
        PERF_METRICS.buildDomTreeBreakdown.averageTimePerNode =
          PERF_METRICS.buildDomTreeBreakdown.totalTime / PERF_METRICS.buildDomTreeBreakdown.buildDomTreeCalls;
      }
  
      PERF_METRICS.buildDomTreeBreakdown.timeInChildCalls =
        PERF_METRICS.buildDomTreeBreakdown.totalTime - PERF_METRICS.buildDomTreeBreakdown.totalSelfTime;
  
      // Add average time per operation to the metrics
      Object.keys(PERF_METRICS.buildDomTreeBreakdown.domOperations).forEach(op => {
        const time = PERF_METRICS.buildDomTreeBreakdown.domOperations[op];
        const count = PERF_METRICS.buildDomTreeBreakdown.domOperationCounts[op];
        if (count > 0) {
          PERF_METRICS.buildDomTreeBreakdown.domOperations[`${op}Average`] = time / count;
        }
      });
  
      // Calculate cache hit rates
      const boundingRectTotal = PERF_METRICS.cacheMetrics.boundingRectCacheHits + PERF_METRICS.cacheMetrics.boundingRectCacheMisses;
      const computedStyleTotal = PERF_METRICS.cacheMetrics.computedStyleCacheHits + PERF_METRICS.cacheMetrics.computedStyleCacheMisses;
  
      if (boundingRectTotal > 0) {
        PERF_METRICS.cacheMetrics.boundingRectHitRate = PERF_METRICS.cacheMetrics.boundingRectCacheHits / boundingRectTotal;
      }
  
      if (computedStyleTotal > 0) {
        PERF_METRICS.cacheMetrics.computedStyleHitRate = PERF_METRICS.cacheMetrics.computedStyleCacheHits / computedStyleTotal;
      }
  
      if ((boundingRectTotal + computedStyleTotal) > 0) {
        PERF_METRICS.cacheMetrics.overallHitRate =
          (PERF_METRICS.cacheMetrics.boundingRectCacheHits + PERF_METRICS.cacheMetrics.computedStyleCacheHits) /
          (boundingRectTotal + computedStyleTotal);
      }
    }
    
    return debugMode ?
      { rootId, map: DOM_HASH_MAP, perfMetrics: PERF_METRICS } :
      { rootId, map: DOM_HASH_MAP };
  };