"""
Runtime detection utilities for fabias.

Provides functions to detect whether the code is running inside a Microsoft Fabric
notebook environment or as a standalone Python application.
"""

from typing import Any, Dict, Optional

# Cache for runtime detection result
_runtime_cache: Optional[bool] = None
_notebookutils_module = None
_sempy_module = None


class Runtime:
    """
    Runtime utilities providing access to Fabric-specific modules.

    Access as properties:
        runtime.notebookutils - The notebookutils module if available
        runtime.sempy - The sempy.fabric module if available
    """

    @property
    def notebookutils(self):
        """
        Get the notebookutils module if available.

        Returns the notebookutils module for use in Fabric runtime,
        or None if not available.

        Returns:
            module or None: The notebookutils module if available, None otherwise.
        """
        global _notebookutils_module

        if _notebookutils_module is not None:
            return _notebookutils_module

        try:
            import importlib

            _notebookutils_module = importlib.import_module("notebookutils")
            return _notebookutils_module
        except ImportError:
            return None

    @property
    def sempy(self):
        """
        Get the sempy.fabric module if available.

        Returns the sempy.fabric module for use in Fabric runtime,
        or None if not available.

        Returns:
            module or None: The sempy.fabric module if available, None otherwise.
        """
        global _sempy_module

        if _sempy_module is not None:
            return _sempy_module

        try:
            import importlib

            _sempy_module = importlib.import_module("sempy.fabric")
            return _sempy_module
        except ImportError:
            return None

    @property
    def isFabric(self):
        """
        Detect if code is running inside a Microsoft Fabric notebook environment.

        This function checks for the presence of Fabric-specific modules and runtime
        context to determine the execution environment. Results are cached for
        performance.

        Detection Strategy:
            1. Check if notebookutils module is importable
            2. Verify notebookutils.runtime.context is accessible
            3. Validate that workspace context information exists

        Returns:
            bool: True if running inside Fabric notebook, False otherwise.

        Examples:
            >>> from fabias import runtime
            >>> if runtime.isFabric:
            ...     # Use Fabric-native features like notebookutils
            ...     token = runtime.notebookutils.credentials.getToken("storage")
            ... else:
            ...     # Use standalone authentication
            ...     token = get_token_via_oauth()

        Notes:
            The result is cached after first call. To force re-detection,
            use `_reset_runtime_cache()` (internal use only).
        """
        global _runtime_cache

        if _runtime_cache is not None:
            return _runtime_cache

        notebookutils = self.notebookutils

        if notebookutils is None:
            _runtime_cache = False
            return False

        # Check if runtime context is available and has workspace info
        try:
            if hasattr(notebookutils, "runtime") and hasattr(notebookutils.runtime, "context"):
                context = notebookutils.runtime.context
                # Verify we have actual Fabric context (not just an empty object)
                if context and (context.get("currentWorkspaceId") or context.get("workspaceId")):
                    _runtime_cache = True
                    return True
        except Exception:
            pass

        _runtime_cache = False
        return False

    @property
    def context(self) -> Dict[str, Any]:
        """
        Get the current Fabric runtime context if available.

        Returns comprehensive context information about the current Fabric
        notebook execution environment, including workspace, lakehouse, and
        notebook identifiers.

        Returns:
            dict: Runtime context containing:
                - workspace_id (str): Current workspace GUID
                - workspace_name (str): Current workspace display name
                - lakehouse_id (str): Default lakehouse GUID if set
                - lakehouse_name (str): Default lakehouse name if set
                - notebook_id (str): Current notebook GUID
                - is_fabric (bool): Whether running in Fabric environment

            Returns minimal dict with is_fabric=False if not in Fabric.

        Examples:
            >>> from fabias import runtime
            >>> ctx = runtime.context
            >>> if ctx['is_fabric']:
            ...     print(f"Running in workspace: {ctx['workspace_name']}")
            ... else:
            ...     print("Running standalone")
        """
        result = {
            "is_fabric": False,
            "workspace_id": None,
            "workspace_name": None,
            "lakehouse_id": None,
            "lakehouse_name": None,
            "notebook_id": None,
        }

        if not self.isFabric:
            return result

        notebookutils = self.notebookutils

        if notebookutils is None:
            return result

        try:
            context = notebookutils.runtime.context
            result["is_fabric"] = True
            result["workspace_id"] = context.get("currentWorkspaceId") or context.get("workspaceId")
            result["workspace_name"] = context.get("currentWorkspaceName") or context.get(
                "workspaceName"
            )
            result["lakehouse_id"] = context.get("defaultLakehouseId") or context.get("lakehouseId")
            result["lakehouse_name"] = context.get("defaultLakehouseName") or context.get(
                "lakehouseName"
            )
            result["notebook_id"] = context.get("notebookId")
        except Exception:
            pass

        return result

    def reset(self):
        """
        Reset the runtime detection cache.

        This is an internal function used primarily for testing. It forces
        the next access to isFabric to re-detect the environment.
        """
        global _runtime_cache, _notebookutils_module, _sempy_module
        _runtime_cache = None
        _notebookutils_module = None
        _sempy_module = None


# Module-level singleton instance
runtime = Runtime()
