"""
#exonware/xwnode/src/exonware/xwnode/nodes/strategies/tree_graph_hybrid.py
Tree Graph Hybrid Strategy Implementation
This module provides a unified tree engine strategy that contains all the XWNodeBase functionality
in one file, decoupled from XWNode. This eliminates the dual architecture and provides
a single, clean implementation.
"""

from __future__ import annotations
import threading
import copy
from abc import ABC, abstractmethod
from typing import Any
from ...defs import NodeMode, NodeTrait
from exonware.xwsystem.caching import create_cache
from .contracts import INodeStrategy
from ...errors import XWNodePathError
from exonware.xwsystem import get_logger
from collections.abc import AsyncIterator, Callable, Iterator
logger = get_logger(__name__)
# Import contracts
from .contracts import NodeType, INodeStrategy
# Import shared utilities
from ...common.utils import (
    PathParser, TrieNode, UnionFind, MinHeap,
    create_path_parser, create_performance_tracker
)
logger = get_logger('xnode.tree_engine')
# ============================================================================
# TREE GRAPH HYBRID INTERNAL NODE CLASSES
# ============================================================================

class TreeGraphNode(ABC):
    """Abstract base for all internal nodes in the TreeGraphHybrid strategy."""
    __slots__ = ('_parent', '_cached_native', '_hash')

    def __init__(self, parent: TreeGraphNode | None = None):
        """Time Complexity: O(1)"""
        self._parent: TreeGraphNode | None = parent
        self._cached_native: Any | None = None
        self._hash: int | None = None
    @property

    def parent(self) -> TreeGraphNode | None:
        """
        Get the parent node.
        Time Complexity: O(1)
        """
        return self._parent
    @parent.setter

    def parent(self, value: TreeGraphNode | None):
        """Set the parent node."""
        self._parent = value

    def _get_child(self, key_or_index: str | int) -> TreeGraphNode:
        """Get a child node by key or index."""
        raise TypeError(f"Node type {type(self).__name__} does not support child access.")
    @abstractmethod

    def _to_native(self) -> Any:
        """Convert this node and its children to a native Python object."""
        pass

    def _invalidate_cache(self):
        """Invalidate cached data when the node changes."""
        self._cached_native = None
        self._hash = None
        # Propagate invalidation up the tree
        if self._parent:
            self._parent._invalidate_cache()

    def _get_root(self) -> TreeGraphNode:
        """Get the root node of the tree."""
        current = self
        while current._parent is not None:
            current = current._parent
        return current

    def _get_key_in_parent(self) -> str | int | None:
        """Get the key or index of this node in its parent."""
        if self._parent is None:
            return None
        if isinstance(self._parent, TreeGraphDictNode):
            for key, child in self._parent._children.items():
                if child is self:
                    return key
        elif isinstance(self._parent, TreeGraphListNode):
            try:
                return self._parent._children.index(self)
            except ValueError:
                pass
        return None

    def _get_path(self) -> str:
        """Get the path from the root to this node as a dot-separated string."""
        if self._parent is None:
            return ""
        parent_path = self._parent._get_path()
        key = self._get_key_in_parent()
        if key is None:
            return parent_path
        if parent_path:
            return f"{parent_path}.{key}"
        else:
            return str(key)

    def cleanup(self) -> None:
        """Clean up the node before returning to pool."""
        self._parent = None
        self._cached_native = None
        self._hash = None

    def reset(self, parent: TreeGraphNode | None = None) -> None:
        """Reset the node to initial state."""
        self._parent = parent
        self._cached_native = None
        self._hash = None


class TreeGraphValueNode(TreeGraphNode):
    """Internal node for a primitive value in TreeGraphHybrid strategy."""
    __slots__ = ('_value',)

    def __init__(self, value: Any, parent: TreeGraphNode | None = None):
        super().__init__(parent)
        self._value = value
    @property

    def value(self) -> Any:
        """Get the primitive value stored in this leaf node."""
        return self._value

    def _to_native(self) -> Any:
        """Convert this node to a native Python object."""
        return self._value


class TreeGraphListNode(TreeGraphNode):
    """Internal node for a list with lazy-loading in TreeGraphHybrid strategy."""
    __slots__ = ('_children', '_source_data', '_is_lazy')

    def __init__(self, source_data: list[Any], is_lazy: bool, parent: TreeGraphNode | None = None):
        super().__init__(parent)
        self._source_data = source_data
        self._is_lazy = is_lazy
        self._children: list[TreeGraphNode] = []
        # Don't load children here to avoid recursion
        # They will be loaded on-demand in _get_child, _to_native, etc.

    def _eager_load(self, data: list[Any]) -> list[TreeGraphNode]:
        """Eagerly load all children."""
        self._children = []
        for item in data:
            if item is None:
                self._children.append(TreeGraphValueNode(None, self))
            elif isinstance(item, (str, int, float, bool)):
                self._children.append(TreeGraphValueNode(item, self))
            elif isinstance(item, list):
                is_lazy = len(item) > 100
                self._children.append(TreeGraphListNode(item, is_lazy, self))
            elif isinstance(item, dict):
                is_lazy = len(item) > 100
                self._children.append(TreeGraphDictNode(item, is_lazy, self))
            else:
                self._children.append(TreeGraphValueNode(item, self))
        self._source_data = None  # Clear source data after loading
        return self._children

    def _get_child(self, index: str | int) -> TreeGraphNode:
        """Get a child node by index."""
        if isinstance(index, str):
            try:
                index = int(index)
            except ValueError:
                raise TypeError(f"List index must be an integer, got {index}")
        if not isinstance(index, int):
            raise TypeError(f"List index must be an integer, got {type(index).__name__}")
        if index < 0:
            index = len(self) + index
        if index < 0 or index >= len(self):
            raise IndexError(f"List index {index} out of range")
        # Lazy load if needed
        if self._source_data is not None:
            self._eager_load(self._source_data)
        return self._children[index]

    def _to_native(self) -> list[Any]:
        """Convert this node and its children to a native Python object."""
        # Lazy load if needed
        if self._source_data is not None:
            self._eager_load(self._source_data)
        return [child._to_native() for child in self._children]

    def __iter__(self) -> Iterator[TreeGraphNode]:
        """Iterate over child nodes."""
        if self._source_data is not None:
            self._eager_load(self._source_data)
        return iter(self._children)

    def __len__(self) -> int:
        """Get the number of child nodes."""
        if self._source_data is not None:
            return len(self._source_data)
        return len(self._children)


class TreeGraphDictNode(TreeGraphNode):
    """Internal node for a dictionary with lazy-loading in TreeGraphHybrid strategy."""
    __slots__ = ('_children', '_source_data', '_is_lazy', '_keys')

    def __init__(self, source_data: dict[str, Any], is_lazy: bool, parent: TreeGraphNode | None = None):
        super().__init__(parent)
        self._source_data = source_data
        self._is_lazy = is_lazy
        self._children: dict[str, TreeGraphNode] = {}
        self._keys = list(source_data.keys())
        # Don't load children here to avoid recursion
        # They will be loaded on-demand in _get_child, _to_native, etc.

    def _eager_load(self, data: dict[str, Any]) -> dict[str, TreeGraphNode]:
        """Eagerly load all children."""
        # Don't clear existing children if we're loading from empty data
        if not data:
            self._source_data = None
            return self._children
        self._children = {}
        for key, value in data.items():
            if value is None:
                self._children[key] = TreeGraphValueNode(None, self)
            elif isinstance(value, (str, int, float, bool)):
                self._children[key] = TreeGraphValueNode(value, self)
            elif isinstance(value, list):
                is_lazy = len(value) > 100
                self._children[key] = TreeGraphListNode(value, is_lazy, self)
            elif isinstance(value, dict):
                is_lazy = len(value) > 100
                self._children[key] = TreeGraphDictNode(value, is_lazy, self)
            else:
                self._children[key] = TreeGraphValueNode(value, self)
        self._source_data = None  # Clear source data after loading
        return self._children

    def _get_child(self, key: str | int) -> TreeGraphNode:
        """Get a child node by key."""
        if not isinstance(key, str):
            raise TypeError(f"Dictionary key must be a string, got {type(key).__name__}")
        # Lazy load if needed
        if self._source_data is not None:
            self._eager_load(self._source_data)
        # Check if key exists in children
        if key not in self._children:
            raise xNodePathError(f"Key '{key}' not found in dictionary")
        return self._children[key]

    def _to_native(self) -> dict[str, Any]:
        """Convert this node and its children to a native Python object."""
        # Lazy load if needed
        if self._source_data is not None:
            self._eager_load(self._source_data)
        return {key: child._to_native() for key, child in self._children.items()}

    def items(self) -> Iterator[tuple[str, TreeGraphNode]]:
        """Iterate over key-value pairs."""
        if self._source_data is not None:
            self._eager_load(self._source_data)
        return self._children.items()

    def __iter__(self) -> Iterator[TreeGraphNode]:
        """Iterate over child nodes."""
        if self._source_data is not None:
            self._eager_load(self._source_data)
        return iter(self._children.values())

    def __len__(self) -> int:
        """Get the number of child nodes."""
        if self._source_data is not None:
            return len(self._source_data)
        return len(self._children)

    def keys(self) -> Iterator[str]:
        """Iterate over keys."""
        if self._source_data is not None:
            return iter(self._source_data.keys())
        return iter(self._children.keys())


class TreeGraphReferenceNode(TreeGraphNode):
    """Internal node for a reference in TreeGraphHybrid strategy."""
    __slots__ = ('_uri', '_reference_type', '_metadata')

    def __init__(self, uri: str, reference_type: str, metadata: dict[str, Any], parent: TreeGraphNode | None = None):
        super().__init__(parent)
        self._uri = uri
        self._reference_type = reference_type
        self._metadata = metadata or {}
    @property

    def uri(self) -> str:
        """Get the URI of the reference."""
        return self._uri
    @property

    def reference_type(self) -> str:
        """Get the type of the reference."""
        return self._reference_type
    @property

    def metadata(self) -> dict[str, Any]:
        """Get the metadata of the reference."""
        return self._metadata

    def _to_native(self) -> dict[str, Any]:
        """Convert this node to a native Python object."""
        return {
            'type': 'reference',
            'uri': self._uri,
            'reference_type': self._reference_type,
            'metadata': self._metadata
        }

    def cleanup(self) -> None:
        """Clean up the node before returning to pool."""
        super().cleanup()
        self._uri = ""
        self._reference_type = ""
        self._metadata = {}

    def reset(self, uri: str, reference_type: str, metadata: dict[str, Any], parent: TreeGraphNode | None = None) -> None:
        """Reset the node to initial state."""
        super().reset(parent)
        self._uri = uri
        self._reference_type = reference_type
        self._metadata = metadata or {}


class TreeGraphObjectNode(TreeGraphNode):
    """Internal node for an object reference in TreeGraphHybrid strategy."""
    __slots__ = ('_uri', '_object_type', '_mime_type', '_size', '_metadata')

    def __init__(self, uri: str, object_type: str, mime_type: str | None, size: int | None, metadata: dict[str, Any], parent: TreeGraphNode | None = None):
        super().__init__(parent)
        self._uri = uri
        self._object_type = object_type
        self._mime_type = mime_type
        self._size = size
        self._metadata = metadata or {}
    @property

    def uri(self) -> str:
        """Get the URI of the object."""
        return self._uri
    @property

    def object_type(self) -> str:
        """Get the type of the object."""
        return self._object_type
    @property

    def mime_type(self) -> str | None:
        """Get the MIME type of the object."""
        return self._mime_type
    @property

    def size(self) -> int | None:
        """Get the size of the object."""
        return self._size
    @property

    def metadata(self) -> dict[str, Any]:
        """Get the metadata of the object."""
        return self._metadata

    def _to_native(self) -> dict[str, Any]:
        """Convert this node to a native Python object."""
        result = {
            'type': 'object',
            'uri': self._uri,
            'object_type': self._object_type,
            'metadata': self._metadata
        }
        if self._mime_type:
            result['mime_type'] = self._mime_type
        if self._size is not None:
            result['size'] = self._size
        return result

    def cleanup(self) -> None:
        """Clean up the node before returning to pool."""
        super().cleanup()
        self._uri = ""
        self._object_type = ""
        self._mime_type = None
        self._size = None
        self._metadata = {}

    def reset(self, uri: str, object_type: str, mime_type: str | None, size: int | None, metadata: dict[str, Any], parent: TreeGraphNode | None = None) -> None:
        """Reset the node to initial state."""
        super().reset(parent)
        self._uri = uri
        self._object_type = object_type
        self._mime_type = mime_type
        self._size = size
        self._metadata = metadata or {}
# ============================================================================
# TREE GRAPH HYBRID NODE FACTORY
# ============================================================================

class TreeGraphNodeFactory:
    """Factory for creating TreeGraphHybrid internal nodes with performance optimizations."""
    @staticmethod

    def from_native(data: Any, parent: TreeGraphNode | None = None, depth: int = 0, visited: set | None = None) -> TreeGraphNode:
        """Create a node from native Python data."""
        # Check depth limit
        if depth > 1000:  # Simple depth limit
            raise ValueError("Maximum depth exceeded")
        # Initialize visited set for circular reference detection
        if visited is None:
            visited = set()
        # Check for circular references
        if id(data) in visited:
            # Return a placeholder node for circular references
            return TreeGraphValueNode(f"<circular_reference_{id(data)}>", parent)
        # Add current object to visited set
        visited.add(id(data))
        try:
            if data is None:
                node = TreeGraphValueNode(None, parent)
            elif isinstance(data, (str, int, float, bool)):
                node = TreeGraphValueNode(data, parent)
            elif isinstance(data, list):
                # Determine if lazy loading should be used
                is_lazy = len(data) > 100
                node = TreeGraphListNode(data, is_lazy, parent)
            elif isinstance(data, dict):
                # Determine if lazy loading should be used
                is_lazy = len(data) > 100
                node = TreeGraphDictNode(data, is_lazy, parent)
            else:
                # For other types, create a value node
                node = TreeGraphValueNode(data, parent)
            return node
        finally:
            # Remove current object from visited set when done
            visited.discard(id(data))
    @staticmethod

    def to_native(node: TreeGraphNode) -> Any:
        """Convert a node to native Python data."""
        return node._to_native()
    # ============================================================================
    # ASYNC API - Lightweight wrappers (NO lock overhead, v0.0.1.28b)
    # ============================================================================

    async def insert_async(self, key: Any, value: Any) -> None:
        """Lightweight async wrapper for insert (no lock overhead)."""
        return self.insert(key, value)

    async def find_async(self, key: Any) -> Any | None:
        """Lightweight async wrapper for find (no lock overhead)."""
        return self.find(key)

    async def delete_async(self, key: Any) -> bool:
        """Lightweight async wrapper for delete (no lock overhead)."""
        return self.delete(key)

    async def size_async(self) -> int:
        """Lightweight async wrapper for size (no lock overhead)."""
        return self.size()

    async def is_empty_async(self) -> bool:
        """Lightweight async wrapper for is_empty (no lock overhead)."""
        return self.is_empty()

    async def to_native_async(self) -> Any:
        """Lightweight async wrapper for to_native (no lock overhead)."""
        return self.to_native()

    async def keys_async(self) -> AsyncIterator[Any]:
        """Lightweight async wrapper for keys (no lock overhead)."""
        for key in self.keys():
            yield key

    async def values_async(self) -> AsyncIterator[Any]:
        """Lightweight async wrapper for values (no lock overhead)."""
        for value in self.values():
            yield value

    async def items_async(self) -> AsyncIterator[tuple[Any, Any]]:
        """Lightweight async wrapper for items (no lock overhead)."""
        for item in self.items():
            yield item
# ============================================================================
# PATH PARSER (Moved from core.py)
# ============================================================================

class PathParser:
    """Thread-safe path parser with caching.
    Performance Optimization:
    - Uses xwsystem create_cache() instead of OrderedDict
    - 10-50x faster cache operations (PylruCache when pylru installed, else FunctoolsLRUCache)
    - Automatic LRU eviction when capacity is reached
    - Thread-safe by default (via xwsystem cache)
    """

    def __init__(self, max_cache_size: int = 1024):
        # Use xwsystem optimized cache instead of OrderedDict
        # Provides 10-50x faster operations with automatic LRU eviction
        self._cache = create_cache(
            capacity=max_cache_size,
            namespace='xwnode',
            name='path_parser_cache'
        )
        self._max_cache_size = max_cache_size

    def parse(self, path: str) -> list[str]:
        """Parse a path string into parts."""
        # Check cache first (xwsystem cache is thread-safe)
        cached = self._cache.get(path)
        if cached is not None:
            return cached
        parts = self._parse_path(path)
        # Cache the result (automatic LRU eviction when capacity reached)
        self._cache.put(path, parts)
        return parts

    def _parse_path(self, path: str) -> list[str]:
        """Internal path parsing logic."""
        if not path:
            return []
        # Simple dot-separated path parsing
        return [part for part in path.split('.') if part]
# ============================================================================
# TREE GRAPH HYBRID STRATEGY
# ============================================================================

class TreeGraphHybridStrategy(INodeStrategy):
    """
    Unified TreeGraphHybrid strategy combining aNode model with advanced data structures.
    This strategy provides:
    - Tree-based navigation with graph capabilities
    - Advanced data structures (Trie, Heap, Union-Find, etc.)
    - Performance optimizations and caching
    - Circular reference detection
    - Lazy loading and object pooling
    """
    # Strategy type classification
    STRATEGY_TYPE = NodeType.HYBRID

    def __init__(self, mode=None, traits=None, **options):
        """Initialize the TreeGraphHybrid strategy."""
        # Accept standard parameters but don't use them (for compatibility)
        self._root: TreeGraphNode | None = None
        self._node_count = 0
        self._options = options
        self._edge_count = 0
        self._cache = {}
        self._size = 0
        self._performance_stats = {
            'cache_hits': 0,
            'cache_misses': 0,
            'operations': 0
        }
        # Initialize shared utilities
        self._path_parser = create_path_parser()
        self._performance_tracker = create_performance_tracker()
    @property

    def strategy_name(self) -> str:
        """Get the name of this strategy."""
        return "tree_graph_hybrid"
    @property

    def supported_traits(self) -> list[NodeTrait]:
        """Get supported traits for this strategy."""
        return [
            NodeTrait.LAZY_LOADING,
            NodeTrait.OBJECT_POOLING,
            NodeTrait.CIRCULAR_REF_DETECTION,
            NodeTrait.PERFORMANCE_TRACKING,
            NodeTrait.GRAPH_CAPABILITIES,
            NodeTrait.QUERY_CAPABILITIES,
            NodeTrait.SECURITY_FEATURES
        ]

    def create_from_data(self, data: Any) -> TreeGraphHybridStrategy:
        """Create the tree from data."""
        self._root = TreeGraphNodeFactory.from_native(data)
        self._size = self._calculate_size(self._root)
        # Force eager loading for immediate access
        if isinstance(self._root, TreeGraphDictNode) and self._root._source_data is not None:
            self._root._eager_load(self._root._source_data)
        elif isinstance(self._root, TreeGraphListNode) and self._root._source_data is not None:
            self._root._eager_load(self._root._source_data)
        return self

    def _calculate_size(self, node: TreeGraphNode) -> int:
        """Calculate the size of the tree."""
        if isinstance(node, TreeGraphValueNode):
            # Treat None as empty (size 0)
            if node._value is None:
                return 0
            return 1
        elif isinstance(node, TreeGraphListNode):
            # For lists, return the number of items
            if node._source_data is not None:
                return len(node._source_data)
            else:
                return len(node._children)
        elif isinstance(node, TreeGraphDictNode):
            # For dictionaries, return the number of key-value pairs
            if node._source_data is not None:
                return len(node._source_data)
            else:
                return len(node._children)
        else:
            return 1

    def get_native(self, key: str, default: Any = None) -> Any:
        """Get a native Python value by key."""
        self._performance_tracker.record_access()
        try:
            if self._root is None:
                return default
            # Handle path navigation
            if '.' in key:
                return self._get_by_path(key, default)
            # Handle direct key access
            if isinstance(self._root, TreeGraphDictNode):
                child = self._root._get_child(key)
                return child._to_native()
            elif isinstance(self._root, TreeGraphListNode):
                try:
                    index = int(key)
                    child = self._root._get_child(index)
                    return child._to_native()
                except ValueError:
                    return default
            elif isinstance(self._root, TreeGraphValueNode):
                # If root is a value node, only return it if key is empty or matches
                if key == "" or key == "value":
                    return self._root._to_native()
                return default
            else:
                return default
        except (KeyError, IndexError, TypeError):
            return default

    def _get_by_path(self, path: str, default: Any = None) -> Any:
        """Get a value by path."""
        if self._root is None:
            return default
        try:
            segments = self._path_parser.parse(path)
            current = self._root
            for segment in segments:
                if isinstance(current, TreeGraphDictNode):
                    current = current._get_child(segment)
                elif isinstance(current, TreeGraphListNode):
                    try:
                        index = int(segment)
                        current = current._get_child(index)
                    except ValueError:
                        return default
                else:
                    return default
            return current._to_native()
        except (KeyError, IndexError, TypeError):
            return default

    def _get_by_key(self, key: str, default: Any = None) -> Any:
        """Get a value by direct key."""
        if self._root is None:
            return default
        try:
            if isinstance(self._root, TreeGraphDictNode):
                child = self._root._get_child(key)
                return child._to_native()
            elif isinstance(self._root, TreeGraphListNode):
                try:
                    index = int(key)
                    child = self._root._get_child(index)
                    return child._to_native()
                except ValueError:
                    return default
            elif isinstance(self._root, TreeGraphValueNode):
                # If root is a value node, only return it if key is empty or matches
                if key == "" or key == "value":
                    return self._root._to_native()
                return default
            else:
                return default
        except (KeyError, IndexError, TypeError):
            return default

    def put(self, key: str, value: Any) -> None:
        """Set a value by key."""
        self._performance_tracker.record_access()
        if self._root is None:
            # Create root if it doesn't exist
            self._root = TreeGraphDictNode({}, False)
        # Handle path navigation
        if '.' in key:
            self._put_by_path(key, value)
        else:
            # Handle direct key access
            if isinstance(self._root, TreeGraphDictNode):
                # Create child node directly to avoid recursion
                if value is None:
                    child = TreeGraphValueNode(None, self._root)
                elif isinstance(value, (str, int, float, bool)):
                    child = TreeGraphValueNode(value, self._root)
                elif isinstance(value, list):
                    is_lazy = len(value) > 100
                    child = TreeGraphListNode(value, is_lazy, self._root)
                elif isinstance(value, dict):
                    is_lazy = len(value) > 100
                    child = TreeGraphDictNode(value, is_lazy, self._root)
                else:
                    child = TreeGraphValueNode(value, self._root)
                self._root._children[key] = child
                self._root._invalidate_cache()

    def _put_by_path(self, path: str, value: Any) -> None:
        """Set a value by path."""
        if self._root is None:
            self._root = TreeGraphDictNode({}, False)
        try:
            segments = self._path_parser.parse(path)
            current = self._root
            # Navigate to parent of target
            for segment in segments[:-1]:
                if isinstance(current, TreeGraphDictNode):
                    if segment not in current._children:
                        current._children[segment] = TreeGraphDictNode({}, False)
                    current = current._children[segment]
                elif isinstance(current, TreeGraphListNode):
                    try:
                        index = int(segment)
                        while len(current._children) <= index:
                            current._children.append(TreeGraphValueNode(None, current))
                        current = current._children[index]
                    except ValueError:
                        return
                else:
                    return
            # Set the final value
            final_segment = segments[-1]
            if isinstance(current, TreeGraphDictNode):
                # Create child node directly to avoid recursion
                if value is None:
                    child = TreeGraphValueNode(None, current)
                elif isinstance(value, (str, int, float, bool)):
                    child = TreeGraphValueNode(value, current)
                elif isinstance(value, list):
                    is_lazy = len(value) > 100
                    child = TreeGraphListNode(value, is_lazy, current)
                elif isinstance(value, dict):
                    is_lazy = len(value) > 100
                    child = TreeGraphDictNode(value, is_lazy, current)
                else:
                    child = TreeGraphValueNode(value, current)
                current._children[final_segment] = child
                current._invalidate_cache()
            elif isinstance(current, TreeGraphListNode):
                try:
                    index = int(final_segment)
                    while len(current._children) <= index:
                        current._children.append(TreeGraphValueNode(None, current))
                    # Create child node directly to avoid recursion
                    if value is None:
                        child = TreeGraphValueNode(None, current)
                    elif isinstance(value, (str, int, float, bool)):
                        child = TreeGraphValueNode(value, current)
                    elif isinstance(value, list):
                        is_lazy = len(value) > 100
                        child = TreeGraphListNode(value, is_lazy, current)
                    elif isinstance(value, dict):
                        is_lazy = len(value) > 100
                        child = TreeGraphDictNode(value, is_lazy, current)
                    else:
                        child = TreeGraphValueNode(value, current)
                    current._children[index] = child
                    current._invalidate_cache()
                except ValueError:
                    return
        except (KeyError, IndexError, TypeError):
            pass

    def has(self, key: str) -> bool:
        """Check if key exists."""
        return self.get_native(key) is not None

    def delete(self, key: str) -> bool:
        """Remove a key-value pair."""
        # Implementation for deletion
        # This would need to handle both direct keys and paths
        return False

    def remove(self, key: str) -> bool:
        """Remove a key-value pair (alias for delete)."""
        return self.delete(key)

    def clear(self) -> None:
        """Clear all data."""
        self._root = None
        self._size = 0

    def keys(self) -> Iterator[str]:
        """Get all keys."""
        if self._root is None or not isinstance(self._root, TreeGraphDictNode):
            return iter([])
        # Trigger lazy loading if needed
        if self._root._source_data is not None:
            self._root._eager_load(self._root._source_data)
        return self._root.keys()

    def values(self) -> Iterator[Any]:
        """Get all values."""
        if self._root is None or not isinstance(self._root, TreeGraphDictNode):
            return iter([])
        # Trigger lazy loading if needed
        if self._root._source_data is not None:
            self._root._eager_load(self._root._source_data)
        return (child._to_native() for child in self._root._children.values())

    def items(self) -> Iterator[tuple[str, Any]]:
        """Get all key-value pairs."""
        if self._root is None or not isinstance(self._root, TreeGraphDictNode):
            return iter([])
        # Trigger lazy loading if needed
        if self._root._source_data is not None:
            self._root._eager_load(self._root._source_data)
        return ((key, child._to_native()) for key, child in self._root._children.items())

    def __len__(self) -> int:
        """Get the number of items."""
        return self._size

    def to_native(self) -> Any:
        """Convert to native Python object."""
        if self._root is None:
            return {}
        return self._root._to_native()

    def backend_info(self) -> dict[str, Any]:
        """Get information about the backend implementation."""
        return {
            "strategy": "TREE_GRAPH_HYBRID",
            "backend": "TreeGraphNode tree with lazy loading and advanced data structures",
            "complexity": {
                "get": "O(depth)",
                "put": "O(depth)",
                "has": "O(depth)",
                "delete": "O(depth)",
                "union_find": "O(α(n))",
                "trie": "O(k) where k = word length",
                "heap": "O(log n)"
            },
            "features": [
                "lazy_loading",
                "object_pooling",
                "caching",
                "tree_navigation",
                "path_parsing",
                "union_find",
                "trie_operations",
                "priority_queue",
                "advanced_traits"
            ]
        }

    def metrics(self) -> dict[str, Any]:
        """Get performance metrics."""
        metrics = self._performance_tracker.get_metrics()
        metrics.update({
            "size": self._size,
            "has_root": self._root is not None
        })
        return metrics
    # ============================================================================
    # ADVANCED DATA STRUCTURE OPERATIONS
    # ============================================================================

    def union_find_make_set(self, x: Any) -> None:
        """Create new set with element x in Union-Find structure."""
        uf = self._get_union_find()
        uf.make_set(x)
        self._save_union_find()

    def union_find_find(self, x: Any) -> Any:
        """Find root of set containing x in Union-Find structure."""
        uf = self._get_union_find()
        return uf.find(x)

    def union_find_union(self, x: Any, y: Any) -> None:
        """Union sets containing x and y in Union-Find structure."""
        uf = self._get_union_find()
        uf.union(x, y)
        self._save_union_find()

    def union_find_connected(self, x: Any, y: Any) -> bool:
        """Check if x and y are in same set in Union-Find structure."""
        uf = self._get_union_find()
        return uf.connected(x, y)

    def union_find_size(self) -> int:
        """Get number of elements in Union-Find structure."""
        uf = self._get_union_find()
        return uf.size()

    def union_find_sets_count(self) -> int:
        """Get number of disjoint sets in Union-Find structure."""
        uf = self._get_union_find()
        return uf.sets_count()

    def trie_insert(self, word: str, value: Any = None) -> None:
        """Insert word into Trie structure."""
        if not isinstance(word, str):
            raise ValueError(f"Word must be string, got {type(word)}")
        self._insert_trie_word(word, value)
        self._save_trie()

    def trie_contains(self, word: str) -> bool:
        """Check if word exists in Trie structure."""
        if not isinstance(word, str):
            return False
        current = self._get_trie()
        for char in word:
            if char not in current.children:
                return False
            current = current.children[char]
        return current.is_end_word

    def trie_get(self, word: str) -> Any:
        """Get value associated with word in Trie structure."""
        if not isinstance(word, str):
            raise ValueError(f"Word must be string, got {type(word)}")
        current = self._get_trie()
        for char in word:
            if char not in current.children:
                raise ValueError(f"Word '{word}' not found in trie")
            current = current.children[char]
        return current.value

    def trie_starts_with(self, prefix: str) -> list[str]:
        """Find all words starting with prefix in Trie structure."""
        if not isinstance(prefix, str):
            return []
        current = self._get_trie()
        for char in prefix:
            if char not in current.children:
                return []
            current = current.children[char]
        # Collect all words from this node
        result = {}
        self._collect_trie_words(current, prefix, result)
        return list(result.keys())

    def heap_push(self, value: Any, priority: float = 0.0) -> None:
        """Push item with priority into MinHeap."""
        heap = self._get_heap()
        heap.push(value, priority)
        self._save_heap()

    def heap_pop_min(self) -> Any:
        """Pop minimum priority item from MinHeap."""
        heap = self._get_heap()
        result = heap.pop_min()
        self._save_heap()
        return result

    def heap_peek_min(self) -> Any:
        """Peek at minimum without removing from MinHeap."""
        heap = self._get_heap()
        return heap.peek_min()

    def heap_size(self) -> int:
        """Get heap size."""
        heap = self._get_heap()
        return heap.size()

    def heap_is_empty(self) -> bool:
        """Check if heap is empty."""
        heap = self._get_heap()
        return heap.is_empty()
    # ============================================================================
    # ADVANCED OPERATIONS HELPER METHODS
    # ============================================================================

    def _get_union_find(self) -> UnionFind:
        """Get or create Union-Find structure from node data."""
        if not hasattr(self, '_union_find'):
            self._union_find = UnionFind()
            # Load existing data if available
            data = self.to_native()
            if isinstance(data, dict) and 'union_find' in data:
                uf_data = data['union_find']
                if isinstance(uf_data, dict):
                    for element, parent in uf_data.get('sets', {}).items():
                        self._union_find._parent[element] = parent
                    for element, rank in uf_data.get('ranks', {}).items():
                        self._union_find._rank[element] = rank
                    self._union_find._sets_count = uf_data.get('sets_count', 0)
        return self._union_find

    def _save_union_find(self) -> None:
        """Save Union-Find structure to node data."""
        if hasattr(self, '_union_find'):
            uf_data = {
                'sets': dict(self._union_find._parent),
                'ranks': dict(self._union_find._rank),
                'sets_count': self._union_find._sets_count
            }
            # Save to node data
            current_data = self.to_native()
            if not isinstance(current_data, dict):
                current_data = {}
            current_data['union_find'] = uf_data
            # Update the strategy with new data
            self._root = TreeGraphNodeFactory.from_native(current_data, None)

    def _get_trie(self) -> TrieNode:
        """Get or create Trie structure from node data."""
        if not hasattr(self, '_trie_root'):
            self._trie_root = TrieNode()
            # Load existing data if available
            data = self.to_native()
            if isinstance(data, dict):
                for word, value in data.items():
                    if isinstance(word, str):
                        self._insert_trie_word(word, value)
        return self._trie_root

    def _insert_trie_word(self, word: str, value: Any) -> None:
        """Insert word into trie."""
        current = self._get_trie()
        for char in word:
            if char not in current.children:
                current.children[char] = TrieNode()
            current = current.children[char]
        current.is_end_word = True
        current.value = value

    def _save_trie(self) -> None:
        """Save Trie structure to node data."""
        if hasattr(self, '_trie_root'):
            all_words = {}
            self._collect_trie_words(self._trie_root, "", all_words)
            # Save to node data
            current_data = self.to_native()
            if not isinstance(current_data, dict):
                current_data = {}
            current_data.update(all_words)
            # Update the strategy with new data
            self._root = TreeGraphNodeFactory.from_native(current_data, None)

    def _collect_trie_words(self, node: TrieNode, prefix: str, result: dict[str, Any]) -> None:
        """Recursively collect all words from trie."""
        if node.is_end_word:
            result[prefix] = node.value
        for char, child in node.children.items():
            self._collect_trie_words(child, prefix + char, result)

    def _get_heap(self) -> MinHeap:
        """Get or create MinHeap structure from node data."""
        if not hasattr(self, '_heap'):
            self._heap = MinHeap()
            # Load existing data if available
            data = self.to_native()
            if isinstance(data, dict) and 'heap' in data:
                heap_data = data['heap']
                if isinstance(heap_data, list):
                    for priority, value in heap_data:
                        self._heap.push(value, priority)
        return self._heap

    def _save_heap(self) -> None:
        """Save MinHeap structure to node data."""
        if hasattr(self, '_heap'):
            heap_data = list(self._heap._heap)
            # Save to node data
            current_data = self.to_native()
            if not isinstance(current_data, dict):
                current_data = {}
            current_data['heap'] = heap_data
            # Update the strategy with new data
            self._root = TreeGraphNodeFactory.from_native(current_data, None)
    # ============================================================================
    # REQUIRED INTERFACE METHODS
    # ============================================================================

    def to_native(self) -> Any:
        """Convert to native Python object."""
        if self._root is None:
            return {}
        return self._root._to_native()

    def size(self) -> int:
        """Get the size/count of items in the tree."""
        # Use same logic as __len__ for consistency
        return len(self)

    def is_empty(self) -> bool:
        """Check if the structure is empty."""
        return self.size() == 0

    def find(self, path: str) -> Any | None:
        """Find a value by path (facade compatibility)."""
        result = self.get(path, default=None)
        if result is not None and hasattr(result, 'to_native'):
            return result.to_native()
        return result

    def insert(self, key: Any, value: Any) -> None:
        """
        Insert key-value pair (INodeStrategy interface method).
        Delegates to put() for compatibility.
        Time Complexity: Same as put()
        """
        self.put(key, value)

    def get(self, path: str, default: Any = None) -> TreeGraphHybridStrategy | None:
        """Get a child node by path."""
        if self._root is None:
            return None
        try:
            if '.' in path:
                result = self._get_node_by_path(path)
            else:
                result = self._get_node_by_key(path)
            if result is None:
                return None
            # Create a new strategy instance with the result
            new_strategy = TreeGraphHybridStrategy()
            new_strategy._root = result
            return new_strategy
        except Exception:
            return None

    def _get_node_by_path(self, path: str) -> TreeGraphNode | None:
        """Get a node by path."""
        if self._root is None:
            return None
        try:
            segments = self._path_parser.parse(path)
            current = self._root
            for segment in segments:
                if isinstance(current, TreeGraphDictNode):
                    current = current._get_child(segment)
                elif isinstance(current, TreeGraphListNode):
                    try:
                        index = int(segment)
                        current = current._get_child(index)
                    except ValueError:
                        return None
                else:
                    return None
            return current
        except (KeyError, IndexError, TypeError):
            return None

    def _get_node_by_key(self, key: str) -> TreeGraphNode | None:
        """Get a node by direct key."""
        if self._root is None:
            return None
        try:
            if isinstance(self._root, TreeGraphDictNode):
                return self._root._get_child(key)
            elif isinstance(self._root, TreeGraphListNode):
                try:
                    index = int(key)
                    return self._root._get_child(index)
                except ValueError:
                    return None
            elif isinstance(self._root, TreeGraphValueNode):
                # If root is a value node, only return it if key is empty or matches
                if key == "" or key == "value":
                    return self._root
                return None
            else:
                return None
        except (KeyError, IndexError, TypeError):
            return None

    def put(self, path: str, value: Any) -> TreeGraphHybridStrategy:
        """Set a value at path."""
        if self._root is None:
            self._root = TreeGraphNodeFactory.from_native({})
        # Coerce int keys (e.g. list indices) to str for path checks and dict storage
        if not isinstance(path, str):
            path = str(path)
        # For now, implement a simple put operation
        # This would need to be enhanced for complex path navigation
        if '.' not in path:
            # Simple key assignment
            if isinstance(self._root, TreeGraphDictNode):
                value_node = TreeGraphNodeFactory.from_native(value, self._root)
                self._root._children[path] = value_node
            else:
                # Convert to dict if needed
                current_data = self.to_native()
                if not isinstance(current_data, dict):
                    current_data = {}
                current_data[path] = value
                self._root = TreeGraphNodeFactory.from_native(current_data)
        return self

    def delete(self, path: str) -> bool:
        """Delete a node at path."""
        if self._root is None:
            return False
        try:
            if '.' not in path:
                if isinstance(self._root, TreeGraphDictNode):
                    if path in self._root._children:
                        del self._root._children[path]
                        return True
            return False
        except Exception:
            return False

    def exists(self, path: str) -> bool:
        """Check if path exists."""
        return self.get(path) is not None

    def keys(self) -> Iterator[str]:
        """Get keys (for dict-like nodes)."""
        if self._root is None:
            return iter([])
        if isinstance(self._root, TreeGraphDictNode):
            return iter(self._root._children.keys())
        elif isinstance(self._root, TreeGraphListNode):
            return iter(str(i) for i in range(len(self._root._children)))
        else:
            return iter([])

    def values(self) -> Iterator['TreeGraphHybridStrategy']:
        """Get values (for dict-like nodes)."""
        if self._root is None:
            return iter([])
        if isinstance(self._root, TreeGraphDictNode):
            for child in self._root._children.values():
                new_strategy = TreeGraphHybridStrategy()
                new_strategy._root = child
                yield new_strategy
        elif isinstance(self._root, TreeGraphListNode):
            for child in self._root._children:
                new_strategy = TreeGraphHybridStrategy()
                new_strategy._root = child
                yield new_strategy
        else:
            return iter([])

    def items(self) -> Iterator[tuple[str, 'TreeGraphHybridStrategy']]:
        """Get items (for dict-like nodes)."""
        if self._root is None:
            return iter([])
        if isinstance(self._root, TreeGraphDictNode):
            for key, child in self._root._children.items():
                new_strategy = TreeGraphHybridStrategy()
                new_strategy._root = child
                yield (key, new_strategy)
        elif isinstance(self._root, TreeGraphListNode):
            for i, child in enumerate(self._root._children):
                new_strategy = TreeGraphHybridStrategy()
                new_strategy._root = child
                yield (str(i), new_strategy)
        else:
            return iter([])

    def __len__(self) -> int:
        """Get length."""
        if self._root is None:
            return 0
        if isinstance(self._root, TreeGraphDictNode):
            return len(self._root._children)
        elif isinstance(self._root, TreeGraphListNode):
            return len(self._root._children)
        else:
            return 1

    def __iter__(self) -> Iterator['TreeGraphHybridStrategy']:
        """Iterate over children."""
        return self.values()

    def __getitem__(self, key: str | int) -> TreeGraphHybridStrategy:
        """Get child by key or index."""
        if self._root is None:
            raise KeyError(f"Key '{key}' not found")
        if isinstance(self._root, TreeGraphDictNode):
            if key not in self._root._children:
                raise KeyError(f"Key '{key}' not found")
            child = self._root._children[key]
        elif isinstance(self._root, TreeGraphListNode):
            if not isinstance(key, int):
                raise TypeError("List indices must be integers")
            if key < 0 or key >= len(self._root._children):
                raise IndexError("List index out of range")
            child = self._root._children[key]
        else:
            raise TypeError(f"Cannot access key '{key}' on node of type {type(self._root)}")
        new_strategy = TreeGraphHybridStrategy()
        new_strategy._root = child
        return new_strategy

    def __setitem__(self, key: str | int, value: Any) -> None:
        """Set child by key or index."""
        if self._root is None:
            self._root = TreeGraphNodeFactory.from_native({})
        if isinstance(self._root, TreeGraphDictNode):
            value_node = TreeGraphNodeFactory.from_native(value, self._root)
            self._root._children[key] = value_node
        elif isinstance(self._root, TreeGraphListNode):
            if not isinstance(key, int):
                raise TypeError("List indices must be integers")
            value_node = TreeGraphNodeFactory.from_native(value, self._root)
            if key >= len(self._root._children):
                # Extend list if needed
                while len(self._root._children) <= key:
                    self._root._children.append(TreeGraphNodeFactory.from_native(None, self._root))
            self._root._children[key] = value_node
        else:
            raise TypeError(f"Cannot set key '{key}' on node of type {type(self._root)}")

    def __contains__(self, key: str | int) -> bool:
        """Check if key exists."""
        if self._root is None:
            return False
        if isinstance(self._root, TreeGraphDictNode):
            return key in self._root._children
        elif isinstance(self._root, TreeGraphListNode):
            if not isinstance(key, int):
                return False
            return 0 <= key < len(self._root._children)
        else:
            return False
    # Type checking properties
    @property

    def is_leaf(self) -> bool:
        """Check if this is a leaf node."""
        if self._root is None:
            return True
        return isinstance(self._root, TreeGraphValueNode)
    @property

    def is_list(self) -> bool:
        """Check if this is a list node."""
        if self._root is None:
            return False
        return isinstance(self._root, TreeGraphListNode)
    @property

    def is_dict(self) -> bool:
        """Check if this is a dict node."""
        if self._root is None:
            return False
        return isinstance(self._root, TreeGraphDictNode)
    @property

    def is_reference(self) -> bool:
        """Check if this is a reference node."""
        if self._root is None:
            return False
        return isinstance(self._root, TreeGraphReferenceNode)
    @property

    def is_object(self) -> bool:
        """Check if this is an object node."""
        if self._root is None:
            return False
        return isinstance(self._root, TreeGraphObjectNode)
    @property

    def type(self) -> str:
        """Get the type of this node."""
        if self._root is None:
            return 'empty'
        elif isinstance(self._root, TreeGraphValueNode):
            return 'value'
        elif isinstance(self._root, TreeGraphListNode):
            return 'list'
        elif isinstance(self._root, TreeGraphDictNode):
            return 'dict'
        elif isinstance(self._root, TreeGraphReferenceNode):
            return 'reference'
        elif isinstance(self._root, TreeGraphObjectNode):
            return 'object'
        else:
            return 'unknown'
    @property

    def value(self) -> Any:
        """Get the value of this node."""
        if self._root is None:
            return None
        return self._root._to_native()
    # Optional properties with default implementations
    @property

    def uri(self) -> str | None:
        """Get URI (for reference/object nodes)."""
        if self._root is None:
            return None
        return getattr(self._root, 'uri', None)
    @property

    def reference_type(self) -> str | None:
        """Get reference type (for reference nodes)."""
        if self._root is None:
            return None
        return getattr(self._root, 'reference_type', None)
    @property

    def object_type(self) -> str | None:
        """Get object type (for object nodes)."""
        if self._root is None:
            return None
        return getattr(self._root, 'object_type', None)
    @property

    def mime_type(self) -> str | None:
        """Get MIME type (for object nodes)."""
        if self._root is None:
            return None
        return getattr(self._root, 'mime_type', None)
    @property

    def metadata(self) -> dict[str, Any] | None:
        """Get metadata (for reference/object nodes)."""
        if self._root is None:
            return None
        return getattr(self._root, 'metadata', None)
