from __future__ import annotations
import logging
from typing import Optional
from zempy.dotnet.clr import CLR

log = logging.getLogger(__name__)

class DotNetSystem:
    """Lazy accessor for the .NET System namespace."""
    _system = None
    _error: Optional[Exception] = None

    @classmethod
    def get(cls):
        """Return the System namespace or None if unavailable."""
        if cls._system is not None:
            return cls._system
        if not CLR.ensure_initialized():
            return None
        try:
            import System  # type: ignore
            cls._system = System
            return System
        except Exception as e:
            cls._error = e
            log.debug(".NET System namespace not available: %s", e)
            return None

    @classmethod
    def is_exception(cls, exc: BaseException) -> bool:
        """True if `exc` is a .NET System.Exception and CLR is active."""
        System = cls.get()
        if System is None:
            return False
        try:
            return isinstance(exc, System.Exception)  # type: ignore[attr-defined]
        except Exception as e:
            log.debug("CLR isinstance check failed: %s", e)
            return False

    @classmethod
    def last_error(cls) -> Optional[Exception]:
        return cls._error

    @classmethod
    def collect_garbage(cls, *, aggressive: bool = True) -> bool:
        """ Trigger .NET garbage collection if the CLR/System namespace is available."""
        try:
            System = cls.get()
            if not System:
                return False
            GC = System.GC
            GC.Collect()
            GC.WaitForPendingFinalizers()
            if aggressive:
                # Second pass is a common pattern to catch objects finalized in the first pass
                GC.Collect()
            return True
        except Exception:
            # Swallow errors: GC shouldn't crash user code paths
            return False

