from __future__ import annotations
import asyncio
from pathlib import Path
import sys
from typing import TYPE_CHECKING, Any, Self
from orionis.console.base.contracts.scheduler import IBaseScheduler
from orionis.container.container import Container
from orionis.container.contracts.service_provider import IServiceProvider
from orionis.container.providers.service_provider import ServiceProvider
from orionis.failure.contracts.handler import IBaseExceptionHandler
from orionis.foundation.contracts.application import IApplication
from orionis.foundation.enums.lifespan import Lifespan
from orionis.foundation.enums.runtimes import Runtime

if TYPE_CHECKING:
    from collections.abc import Callable
    from orionis.console.contracts.kernel import IKernelCLI
    from orionis.services.cache.contracts.file_based_cache import IFileBasedCache

_SENTINEL = object()

class Application(Container, IApplication):

    # ruff: noqa: PLC0415, PERF203, SLF001, PLR2004, ANN401

    # --- ASGI and RSGI Protocol Handlers ---

    async def __call__(
        self,
        scope: dict,
        receive: Callable[[], Any],
        send: Callable[[dict], Any],
    ) -> Any:
        """
        Dispatch the ASGI application call based on the scope type.

        Parameters
        ----------
        scope : dict
            The ASGI connection scope.
        receive : Callable[[], Any]
            The ASGI receive callable.
        send : Callable[[dict], Any]
            The ASGI send callable.

        Returns
        -------
        Any
            The result of the ASGI application call, or None if the scope type
            is not supported.
        """
        # Determine the scope type and dispatch accordingly
        scope_type = scope.get("type")

        # Handle lifespan events for application startup and shutdown.
        if scope_type == "lifespan":
            return await self.__asgi_lifespan__(receive, send)

        # Handle HTTP requests using the ASGI protocol.
        if scope_type == "http":
            return await self.handleASGI(scope, receive, send)

        # For unsupported scope types, return None
        # (ASGI spec allows ignoring unknown types).
        return None

    async def __asgi_lifespan__(
        self,
        receive: Callable[[], Any],
        send: Callable[[dict], Any],
    ) -> None:
        """
        Handle ASGI lifespan events for startup and shutdown.

        Parameters
        ----------
        receive : Callable[[], Any]
            The ASGI receive callable.
        send : Callable[[dict], Any]
            The ASGI send callable.

        Returns
        -------
        None
            This method does not return a value. It manages ASGI lifespan events.
        """
        # Map ASGI lifespan events to internal handlers
        handler_map = {
            Lifespan.STARTUP: self.__onStartup,
            Lifespan.SHUTDOWN: self.__onShutdown,
        }

        while True:
            message = await receive()
            message_type = message.get("type")

            # Exit on disconnect event
            if message_type == "lifespan.disconnect":
                return

            try:
                event = Lifespan(message_type)
            except ValueError:
                # Ignore unknown events
                continue

            handler = handler_map.get(event)
            if handler is None:
                continue

            try:
                await handler(runtime=Runtime.HTTP)
                await send({"type": f"{message_type}.complete"})

                if event is Lifespan.SHUTDOWN:
                    # Exit after shutdown event
                    return

            except (RuntimeError, TypeError, ValueError) as exc:

                # Log the error and send a failure message back to the ASGI server.
                error_msg = str(exc)
                await send({
                    "type": f"{message_type}.failed",
                    "message": error_msg,
                })
                return

    async def __rsgi__(
        self,
        scope: object,
        protocol: object,
    ) -> object:
        """
        Handle the RSGI protocol for incoming requests.

        Parameters
        ----------
        scope : object
            The connection scope information.
        protocol : object
            The protocol instance for the connection.

        Returns
        -------
        object
            The result of handling the RSGI request.
        """
        # Delegate to the HTTP kernel's RSGI handler.
        return await self.handleRSGI(scope, protocol)

    def __rsgi_init__(
        self,
        loop: asyncio.AbstractEventLoop,
    ) -> None:
        """
        Initialize the RSGI application lifecycle and execute startup callbacks.

        Parameters
        ----------
        loop : asyncio.AbstractEventLoop
            The event loop for asynchronous execution.

        Returns
        -------
        None
            This method executes startup callbacks and does not return a value.
        """
        # Trigger application startup lifecycle and run all startup callbacks.
        loop.run_until_complete(
            self.__onStartup(runtime=Runtime.HTTP),
        )

    def __rsgi_del__(
        self,
        loop: asyncio.AbstractEventLoop,
    ) -> None:
        """
        Execute the RSGI application shutdown lifecycle.

        Parameters
        ----------
        loop : asyncio.AbstractEventLoop
            The event loop for asynchronous execution.

        Returns
        -------
        None
            This method executes shutdown callbacks and does not return a value.
        """
        # Trigger application shutdown lifecycle and run all shutdown callbacks.
        loop.run_until_complete(
            self.__onShutdown(runtime=Runtime.HTTP),
        )

    # --- Application State Properties ---

    @property
    def isBooted(self) -> bool:
        """
        Check if the application service providers have been booted.

        Returns
        -------
        bool
            True if all service providers have been booted and the application is
            ready for use; otherwise, False.
        """
        return self.__booted

    @property
    def startAt(self) -> int:
        """
        Return the application startup timestamp in nanoseconds.

        Returns
        -------
        int
            Timestamp in nanoseconds since Unix epoch when the application
            instance was initialized.
        """
        return self.__start_at

    @property
    def routeHealthCheck(self) -> str:
        """
        Return the health check route configured for the application.

        Returns
        -------
        str
            The path configured for health checks. Returns "/health" if not set
            in the routing configuration.
        """
        # Retrieve health check route from routing configuration, default to "/health"
        routing_config: dict = self.__bootstrap.get("routing", {})
        return routing_config.get("health", "/health")

    @property
    def cacheConfiguration(self) -> dict[str, Any]:
        """
        Return the current cache configuration settings.

        Returns
        -------
        dict[str, Any]
            Dictionary containing cache configuration settings including folder
            path, monitored directories, and monitored files. Returns empty
            dictionary if caching is not configured.
        """
        # Return empty configuration if cache folder is not set
        if self.__cache_folder is None:
            return {}

        # Return current cache configuration settings
        return {
            "folder": self.__cache_folder,
            "monitored_dirs": self.__cache_monitor_dirs or [],
            "monitored_files": self.__cache_monitor_files or [],
        }

    @property
    def entryPoint(self) -> str | None:
        """
        Return the entry point module path where the application was created.

        Returns
        -------
        str | None
            The module path (dot notation, e.g., 'folder.subfolder.file') where
            the application instance was created, or None if not available.
        """
        # Return None if the creation stack is not set
        if not self.__entry_point:
            return None

        # Get the root path from configuration or use current working directory
        root = self.path("root") or Path.cwd()
        abs_path = Path(self.__entry_point).resolve()

        # Compute the relative path from the root to the entry point,
        # or use the filename if not relative
        try:
            rel_path = abs_path.relative_to(root)
        except ValueError:
            rel_path = abs_path.name

        # Remove file extension and convert to module path notation
        if isinstance(rel_path, Path) and rel_path.suffix:
            rel_path = rel_path.with_suffix("")

        # Convert the relative path to module notation (dot-separated) and return
        module_path = (
            ".".join(rel_path.parts)
            if isinstance(rel_path, Path)
            else ".".join(Path(rel_path).parts)
        )

        # Return the module path in dot notation, or None if it cannot be determined
        return f"{module_path}:app"

    def __init__(
        self,
    ) -> None:
        """
        Initialize the Application container with default configuration.

        Set up the initial application state, including service provider list,
        configuration storage, and boot status. Implement a singleton pattern
        to prevent multiple initializations of the same application instance.

        Returns
        -------
        None
            This method initializes internal state and does not return a value.
        """
        # Call the parent Container initializer
        super().__init__()

        # Ensure singleton initialization for the Application instance
        if not hasattr(self, "_Application__initialized"):

            # Check Python version compatibility for the framework.
            if sys.version_info < (3, 14):
                raise RuntimeError("Orionis Framework requires Python 3.14 or higher.")

            # Initialize application startup timestamp
            self.__start_at: int = self.__startAt()

            # Initialize cache-related attributes
            self.__cache_folder: Path | None = None
            self.__cache_monitor_dirs: list[Path] = []
            self.__cache_monitor_files: list[Path] = []
            self.__cache_driver: IFileBasedCache | None = None
            self.__cached: bool = False

            # Initialize resolved service instances
            self.__scheduler_resolved: IBaseScheduler | None = None
            self.__exception_handler_resolved: IBaseExceptionHandler | None = None

            # Initialize application state flags
            self.__booted: bool = False
            self.__configured: bool = False

            # Initialize configuration dictionaries
            self.__bootstrap: dict[str, Any] = {}
            self.__runtime_config: dict[str, Any] = {}

            # Initialize kernels cache
            self.__kernel_cli: Callable | None = None
            self.__kernel_http_rsgi: Callable | None = None
            self.__kernel_http_asgi: Callable | None = None

            # Initialize deferred providers cache
            self.__cache_resolved_providers: set[str] = set()
            self.__pending_boot_providers: list[type[IServiceProvider]] = []

            # Initialize providers registry sentinel
            self.__providers_registry_initialized: bool = False

            # Store the file path where the application was started.
            self.__entry_point: str | None = None

            # Set up lifecycle callbacks lists
            self.__on_startup_callbacks: dict = {"cli": [], "http": []}
            self.__on_shutdown_callbacks: dict = {"cli": [], "http": []}

            # Mark the Application as initialized to enforce singleton behavior
            self._Application__initialized = True

    # --- Lifecycle Callbacks Registration Methods ---

    def onStartup(
        self,
        cli: list[tuple[Callable[..., Any], list[Any]]] | None = None,
        http: list[tuple[Callable[..., Any], list[Any]]] | None = None,
    ) -> Self:
        """
        Register startup lifecycle callbacks for CLI and HTTP.

        Parameters
        ----------
        cli : list[tuple[Callable[..., Any], list[Any]]] | None
            List of tuples for CLI startup callbacks, each containing a callable
            and its arguments.
        http : list[tuple[Callable[..., Any], list[Any]]] | None
            List of tuples for HTTP startup callbacks, each containing a callable
            and its arguments.

        Returns
        -------
        Self
            The current Application instance for method chaining.

        Raises
        ------
        TypeError
            If any provided callback is not callable or not a tuple.
        """
        # Validate input types for callbacks
        if (
            (cli is not None and not isinstance(cli, list)) or
            (http is not None and not isinstance(http, list))
        ):
            error_msg = (
                "Expected a list of (callable, args) tuples for startup callbacks."
            )
            raise TypeError(error_msg)

        # Register CLI startup callbacks
        for callback_tuple in cli:
            if not isinstance(callback_tuple, tuple):
                error_msg = (
                    "Each startup callback must be a tuple of (callable, args)."
                )
                raise TypeError(error_msg)
            self.__on_startup_callbacks[Runtime.CLI].append(
                self.__extractFunctionTuple(callback_tuple),
            )

        # Register HTTP startup callbacks
        for callback_tuple in http:
            if not isinstance(callback_tuple, tuple):
                error_msg = (
                    "Each startup callback must be a tuple of (callable, args)."
                )
                raise TypeError(error_msg)
            self.__on_startup_callbacks[Runtime.HTTP].append(
                self.__extractFunctionTuple(callback_tuple),
            )

        # Return self for method chaining
        return self

    def onShutdown(
        self,
        cli: list[tuple[Callable[..., Any], list[Any]]] | None = None,
        http: list[tuple[Callable[..., Any], list[Any]]] | None = None,
    ) -> Self:
        """
        Register shutdown lifecycle callbacks for CLI and HTTP.

        Parameters
        ----------
        cli : list[tuple[Callable[..., Any], list[Any]]] | None
            List of tuples for CLI shutdown callbacks, each containing a callable
            and its arguments.
        http : list[tuple[Callable[..., Any], list[Any]]] | None
            List of tuples for HTTP shutdown callbacks, each containing a callable
            and its arguments.

        Returns
        -------
        Self
            The current Application instance for method chaining.

        Raises
        ------
        TypeError
            If any provided callback is not callable or not a tuple.
        """
        # Validate input types for callbacks
        if (
            (cli is not None and not isinstance(cli, list)) or
            (http is not None and not isinstance(http, list))
        ):
            error_msg = (
                "Expected a list of (callable, args) tuples for shutdown callbacks."
            )
            raise TypeError(error_msg)

        # Register CLI shutdown callbacks
        for callback_tuple in cli:
            if not isinstance(callback_tuple, tuple):
                error_msg = (
                    "Each shutdown callback must be a tuple of (callable, args)."
                )
                raise TypeError(error_msg)
            self.__on_shutdown_callbacks[Runtime.CLI].append(
                self.__extractFunctionTuple(callback_tuple),
            )

        # Register HTTP shutdown callbacks
        for callback_tuple in http:
            if not isinstance(callback_tuple, tuple):
                error_msg = (
                    "Each shutdown callback must be a tuple of (callable, args)."
                )
                raise TypeError(error_msg)
            self.__on_shutdown_callbacks[Runtime.HTTP].append(
                self.__extractFunctionTuple(callback_tuple),
            )

        # Return self for method chaining
        return self

    def __extractFunctionTuple(
        self,
        callback_tuple: tuple[Callable[..., Any], list[Any]],
    ) -> tuple[Callable[..., Any], list[Any], dict[str, Any]]:
        """
        Extract the callable, arguments, and keyword arguments from a callback tuple.

        Parameters
        ----------
        callback_tuple : tuple[Callable[..., Any], list[Any]]
            Tuple containing a callable and a list of arguments.

        Returns
        -------
        tuple[Callable[..., Any], list[Any], dict[str, Any]]
            Tuple with the callable, its arguments, and a dictionary of keyword
            arguments (empty if not provided).
        """
        # Unpack the function, args, and kwargs from the tuple
        func = callback_tuple[0]
        args = callback_tuple[1] if len(callback_tuple) > 1 else []
        kwargs = callback_tuple[2] if len(callback_tuple) > 2 else {}
        return func, args, kwargs

    async def __onStartup(
        self,
        runtime: str,
    ) -> None:
        """
        Initialize the RSGI application lifecycle and execute startup callbacks.

        Parameters
        ----------
        loop : asyncio.AbstractEventLoop
            The event loop for asynchronous execution.

        Returns
        -------
        None
            This method executes startup callbacks and does not return a value.
        """
        # Boot eager service providers in current runtime
        # before handling startup callbacks.
        await self.__bootEagerProviders()

        # Trigger startup lifecycle events and execute registered startup callbacks
        if runtime == Runtime.HTTP:

            # Import startup generator and async handler for lifecycle management.
            from orionis.foundation.lifespan.startup import startup_orionis_generator
            from contextlib import suppress

            # Start the Orionis startup generator.
            startup_gen = startup_orionis_generator(self)
            next(startup_gen)

            # Execute all registered startup callbacks (sync or async).
            for tuple_func in self.__on_startup_callbacks[runtime]:
                func, args, kwargs = tuple_func
                if asyncio.iscoroutinefunction(func):
                    await func(*args, **kwargs)
                else:
                    func(*args, **kwargs)

            # Finalize the startup generator.
            with suppress(StopIteration):
                next(startup_gen)

        if runtime == Runtime.CLI:

            # Execute all registered startup callbacks (sync or async).
            for tuple_func in self.__on_startup_callbacks[runtime]:
                func, args, kwargs = tuple_func
                if asyncio.iscoroutinefunction(func):
                    await func(*args, **kwargs)
                else:
                    func(*args, **kwargs)

    async def __onShutdown(
        self,
        runtime: str,
    ) -> None:
        """
        Execute shutdown callbacks for the RSGI application lifecycle.

        Parameters
        ----------
        loop : asyncio.AbstractEventLoop
            The event loop for asynchronous execution.

        Returns
        -------
        None
            This method executes shutdown callbacks and does not return a value.
        """
        # Trigger shutdown lifecycle events and execute registered shutdown callbacks
        if runtime == Runtime.HTTP:

            # Import shutdown generator and async handler for lifecycle management.
            from orionis.foundation.lifespan.shutdown import shutdown_orionis_generator
            from contextlib import suppress

            # Start the Orionis shutdown generator.
            shutdown_gen = shutdown_orionis_generator(self)
            next(shutdown_gen)

            # Execute all registered shutdown callbacks (sync or async).
            for tuple_func in self.__on_shutdown_callbacks[runtime]:
                func, args, kwargs = tuple_func
                if asyncio.iscoroutinefunction(func):
                    await func(*args, **kwargs)
                else:
                    func(*args, **kwargs)

            # Finalize the shutdown generator.
            with suppress(StopIteration):
                next(shutdown_gen)

        if runtime == Runtime.CLI:

            # Execute all registered shutdown callbacks (sync or async).
            for tuple_func in self.__on_shutdown_callbacks[runtime]:
                func, args, kwargs = tuple_func
                if asyncio.iscoroutinefunction(func):
                    await func(*args, **kwargs)
                else:
                    func(*args, **kwargs)

    # --- Default Configuration Setup Methods ---

    def __defaultBootstrap(
        self,
    ) -> dict[str, Any]:
        """
        Return the default bootstrap configuration dictionary.

        Create and return the default bootstrap configuration containing all
        necessary sections for application initialization including config,
        exception handler, kernels, paths, providers, routing, and scheduler.

        Returns
        -------
        dict[str, Any]
            The default bootstrap configuration dictionary with all core
            sections initialized.
        """
        # Import default constants for bootstrap configuration
        from orionis.foundation.core_exception_handler import CORE_EXCEPTION_HANDLER
        from orionis.foundation.core_kernels import CORE_KERNELS
        from orionis.foundation.core_scheduler import CORE_SCHEDULER
        from orionis.support.structures.freezer import FreezeThaw

        # Deep unfreeze core configurations for mutability
        core_exception_handler = FreezeThaw.thaw(CORE_EXCEPTION_HANDLER)
        core_scheduler = FreezeThaw.thaw(CORE_SCHEDULER)
        core_kernels = FreezeThaw.thaw(CORE_KERNELS)

        # Return the default bootstrap dictionary with all core sections
        return {
            "commands": {},
            "config": {},
            "exception_handler": core_exception_handler,
            "kernels": core_kernels,
            "paths": {},
            "providers": {},
            "routing": {},
            "scheduler": core_scheduler,
        }

    def __ensureDefaultBootstrap(
        self,
    ) -> None:
        """
        Initialize the bootstrap configuration with default values.

        Initialize the internal bootstrap configuration dictionary with the default
        bootstrap configuration if it is currently empty. This ensures the
        application has a valid configuration structure before any customization.

        Returns
        -------
        None
            This method does not return a value. It modifies the internal bootstrap
            configuration state in place.
        """
        # If bootstrap is not empty, return immediately
        if self.__bootstrap:
            return

        # Initialize bootstrap configuration if not already set
        self.__bootstrap = self.__defaultBootstrap()

    def __ensureDefaultPaths(
        self,
    ) -> None:
        """
        Ensure default application paths are set in the bootstrap configuration.

        Initialize the 'paths' key in the bootstrap dictionary using default
        configuration paths if it is missing or empty.

        Returns
        -------
        None
            This method does not return a value. It modifies the internal
            bootstrap state to ensure paths are set.
        """
        # If paths exist and are not empty, return immediately
        if self.__bootstrap.get("paths"):
            return

        # Set default paths if not already present in bootstrap configuration
        self.withConfigPaths()

    # --- Utility Functions for Application Loading ---

    def __startAt(
        self,
    ) -> int:
        """
        Return the application startup timestamp in nanoseconds.

        Returns
        -------
        int
            The timestamp in nanoseconds since the Unix epoch when the
            application instance was initialized.
        """
        # Lazy import
        import time

        # Return the current time in nanoseconds
        return time.time_ns()

    def __assertConfigMutable(
        self,
    ) -> None:
        """
        Assert that configuration is mutable before modification.

        Raises
        ------
        RuntimeError
            If attempting to modify configuration after application boot.

        Returns
        -------
        None
            This method does not return a value. Raises if configuration is locked.
        """
        # Prevent configuration changes after boot
        if self.__booted:
            error_msg = (
                "Cannot modify configuration after application has been booted."
            )
            raise RuntimeError(error_msg)

        # Initialize bootstrap configuration if not already set
        self.__ensureDefaultBootstrap()

    def __lockConfig(
        self,
    ) -> None:
        """
        Deeply freeze and lock the application configuration.

        Deeply freeze the internal bootstrap configuration to prevent further
        modifications. Sets the booted flag to True, indicating that the
        application's configuration is finalized and cannot be changed.

        Returns
        -------
        None
            This method does not return a value. The configuration is locked
            in-place.
        """
        # Deep freeze the bootstrap configuration to make it immutable
        from orionis.support.structures.freezer import FreezeThaw
        self.__bootstrap = FreezeThaw.freeze(self.__bootstrap)

    # --- Application Cache Handling Driver (If Configured) ---

    def withCache(
        self,
        path: Path,
        filename: str | None = None,
        monitored_dirs: list[Path] | None = None,
        monitored_files: list[Path] | None = None,
    ) -> Self:
        """
        Register cache configuration for the application.

        Parameters
        ----------
        path : Path
            The directory path for cache storage.
        filename : str | None, optional
            The cache filename. Defaults to "setup" if not provided.
        monitored_dirs : list[Path] | None, optional
            List of directories to monitor for cache invalidation.
        monitored_files : list[Path] | None, optional
            List of files to monitor for cache invalidation.

        Returns
        -------
        Application
            The current Application instance for method chaining.

        Raises
        ------
        TypeError
            If any argument is not of the expected type.
        """
        # Lazy import
        from orionis.services.cache.file_based_cache import FileBasedCache

        # Store cache settings for later use
        self.__cache_driver = FileBasedCache(
            path=path,
            filename=filename or "startup",
            monitored_dirs=monitored_dirs or [],
            monitored_files=monitored_files or [],
        )

        # Retrieve current cache settings
        current_cache = self.__cache_driver.get()

        # If valid cache exists, store it and mark as cached
        if current_cache is not None:
            self.__bootstrap = current_cache
            self.__cached = True
            self.__commitConfig()

        # Store cache monitoring settings
        self.__cache_folder = path
        self.__cache_monitor_dirs = monitored_dirs or []
        self.__cache_monitor_files = monitored_files or []

        # Return self for method chaining
        return self

    def __saveCache(
        self,
    ) -> None:
        """
        Save the current bootstrap configuration to cache if caching is enabled.

        Returns
        -------
        None
            This method does not return a value. It saves the configuration
            to cache if a cache driver is configured.
        """
        # Lazy import
        from copy import deepcopy

        # If no cache driver is configured, do nothing
        if self.__cache_driver is None:
            return

        # Save the current bootstrap configuration to cache
        self.__cache_driver.save(deepcopy(self.__bootstrap))

    # --- Service Provider Bootstrapping Logic ---

    def withProviders(
        self,
        providers: type[IServiceProvider] | list[type[IServiceProvider]],
    ) -> Self:
        """
        Register one or more service providers for the application.

        Parameters
        ----------
        providers : type[IServiceProvider] | list[type[IServiceProvider]]
            A single service provider class or a list of service provider classes
            to register. Each must inherit from IServiceProvider.

        Returns
        -------
        Application
            The current Application instance for method chaining.

        Raises
        ------
        TypeError
            If any argument is not a class or does not inherit from IServiceProvider.
        KeyError
            If a provider is already registered.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Normalize input to a list of providers for uniform processing
        if isinstance(providers, type):
            providers = [providers]
        elif not isinstance(providers, list):
            error_msg = (
                "Expected IServiceProvider class or list, got "
                f"{type(providers).__name__}"
            )
            raise TypeError(error_msg)

        # Register each provider using the internal storage method
        for provider in providers:
            self.__storeProviderInstance(provider)

        # Return self instance for method chaining
        return self

    def getDeferredProviders(self) -> dict:
        """
        Return the dictionary of deferred service providers.

        Returns
        -------
        dict
            Dictionary containing deferred service providers.
        """
        # Access the deferred providers from the bootstrap configuration.
        return self.__bootstrap.get("providers", {}).get("deferred", {})

    def __loadCoreProviders(
        self,
    ) -> None:
        """
        Load and register core framework service providers.

        Imports and registers essential service providers required for
        framework operation, including console, dumping, path resolution,
        progress bars, workers, logging, and testing capabilities. Ensures
        core services are available before user-defined providers.

        Parameters
        ----------
        self : ProvidersLoader
            Instance of ProvidersLoader.

        Returns
        -------
        None
            Modifies the internal providers registry in-place.
        """
        # Import core providers list [MappingProxyType]
        from orionis.foundation.core_providers import CORE_PROVIDERS

        # Register each provider in the appropriate registry
        for provider in CORE_PROVIDERS:
            self.__storeProviderInstance(provider)

    def __ensureProvidersRegistryStructure(
        self,
    ) -> None:
        """
        Ensure the providers registry structure is properly initialized.

        Initialize the eager and deferred provider registries in the bootstrap
        configuration if they do not already exist. This method creates the
        necessary dictionary structure for storing service provider information
        and prevents duplicate initialization through a sentinel attribute.

        Returns
        -------
        None
            This method does not return a value. It modifies internal state.
        """
        # Ensure eager and deferred provider registries exist
        if not self.__providers_registry_initialized:
            if "eager" not in self.__bootstrap["providers"]:
                self.__bootstrap["providers"]["eager"] = {}
            if "deferred" not in self.__bootstrap["providers"]:
                self.__bootstrap["providers"]["deferred"] = {}
            self.__providers_registry_initialized = True

    def __validateProviderClass(
        self,
        provider_class: type[IServiceProvider],
    ) -> None:
        """
        Validate that the provider class meets IServiceProvider requirements.

        Parameters
        ----------
        provider_class : type[IServiceProvider]
            The service provider class to validate.

        Returns
        -------
        None
            This method does not return a value. Raises exceptions if validation
            fails.

        Raises
        ------
        TypeError
            If the provider is not a class or not a subclass of IServiceProvider.
        """
        # Validate that the provider is a class
        if not isinstance(provider_class, type):
            error_msg = (
                f"Expected IServiceProvider class, got "
                f"{type(provider_class).__name__}"
            )
            raise TypeError(error_msg)

        # Validate that the provider is a subclass of IServiceProvider
        if not issubclass(provider_class, IServiceProvider):
            error_msg = (
                f"Expected IServiceProvider subclass, got "
                f"{type(provider_class).__name__}"
            )
            raise TypeError(error_msg)

    def __storeEagerProviderInstance(
        self,
        provider: type[IServiceProvider],
    ) -> None:
        """
        Store an eager service provider instance in the eager registry.

        Parameters
        ----------
        provider : type[IServiceProvider]
            The service provider class to register.

        Returns
        -------
        None
            This method does not return a value. It modifies the internal eager
            providers registry in-place.

        Raises
        ------
        TypeError
            If the provider is not a class or not a subclass of IServiceProvider.
        """
        # Lazy import
        from collections import OrderedDict

        # Prepare eager provider registry
        eager = OrderedDict(self.__bootstrap["providers"]["eager"])

        # Extract module and class name for storage
        module = provider.__module__
        class_name = provider.__name__
        provider_full_path = f"{module}.{class_name}"

        # Remove if already exists to prevent duplicates
        eager.pop(provider_full_path, None)

        # Insert at the beginning to prioritize this provider
        eager[provider_full_path] = {
            "module": provider.__module__,
            "class": provider.__name__,
        }
        eager.move_to_end(provider_full_path, last=False)

        # Save the updated eager providers registry
        self.__bootstrap["providers"]["eager"] = eager

    def __storeDeferredProviderInstance(
        self,
        provider: type[IServiceProvider],
    ) -> None:
        """
        Store a deferred service provider instance in the deferred registry.

        Parameters
        ----------
        provider : type[IServiceProvider]
            The service provider class to register.

        Returns
        -------
        None
            This method does not return a value.

        Raises
        ------
        TypeError
            If the provider is not a class or not a subclass of IServiceProvider.
        """
        # Prepare deferred provider registry
        deferred: dict = self.__bootstrap["providers"]["deferred"]

        # Extract module and class name for storage
        module = provider.__module__
        class_name = provider.__name__
        provider_full_path = f"{module}.{class_name}"

        # For deferred providers, get their provides() method result
        provider_instance = provider(self)
        provides_method = getattr(provider_instance, "provides", None)
        if not callable(provides_method):
            error_msg = (
                f"Deferred provider {provider_full_path} must have a "
                "'provides' method"
            )
            raise TypeError(error_msg)

        # Register each service provided by the deferred provider
        provided_services:list = provides_method()
        for service in provided_services:
            service_full_path = f"{service.__module__}.{service.__name__}"
            deferred.pop(service_full_path, None)
            deferred[service_full_path] = {
                "module": module,
                "class": class_name,
            }

    def __storeProviderInstance(
        self,
        provider: type[IServiceProvider],
    ) -> None:
        """
        Store a service provider instance in the appropriate registry.

        Register the provider class in either the eager or deferred registry based
        on its inheritance hierarchy. Validates provider type and ensures proper
        registry structure before storage.

        Parameters
        ----------
        provider : type[IServiceProvider]
            The service provider class to register.

        Returns
        -------
        None
            This method does not return a value.

        Raises
        ------
        TypeError
            If the provider is not a class or not a subclass of IServiceProvider.
        """
        # Lazy import
        from orionis.container.providers.deferrable_provider import DeferrableProvider

        # Ensure providers registry structure is initialized
        self.__ensureProvidersRegistryStructure()

        # Validate the provider class meets requirements
        self.__validateProviderClass(provider)

        # Register as deferred or eager based on provider inheritance
        if issubclass(provider, DeferrableProvider):
            self.__storeDeferredProviderInstance(provider)
        else:
            self.__storeEagerProviderInstance(provider)

    def __discoverProviders(
        self,
        modules: set[str],
    ) -> None:
        """
        Discover and register service providers from the providers folder.

        Imports each discovered module, identifies classes that are
        subclasses of ServiceProvider, and registers them in the appropriate
        registry based on whether they are deferred or immediate providers.

        Parameters
        ----------
        self : ProvidersLoader
            Instance of ProvidersLoader.

        Returns
        -------
        None
            Modifies the internal providers registry in-place.
        """
        # Lazy import
        from orionis.container.providers.deferrable_provider import DeferrableProvider

        # Import each module and register its service providers
        for module_name in modules:
            module = __import__(module_name, fromlist=["*"])
            for attribute_name in dir(module):
                attribute = getattr(module, attribute_name)
                if (
                    isinstance(attribute, type) and
                    issubclass(attribute, ServiceProvider) and
                    attribute is not ServiceProvider and
                    attribute is not DeferrableProvider
                ):
                    self.__storeProviderInstance(attribute)

    def __loadProviders(
        self,
    ) -> None:
        """
        Load and register all service providers from the providers directory.

        Discovers provider modules, registers provider classes, and loads core
        framework providers. This ensures that all service providers are available
        for dependency injection and application bootstrapping.

        Parameters
        ----------
        self : Application
            The current application instance.

        Returns
        -------
        None
            This method does not return any value. It updates the internal
            providers registry in place.
        """
        # Lazy import
        from orionis.services.introspection.modules.engine import ModuleEngine

        # Discover provider modules in the providers directory
        config_paths = self.__bootstrap["paths"]
        providers_modules: set[str] = ModuleEngine.scan(
            app_root=config_paths["root"],
            tarjet_path=config_paths["providers"],
        )

        # Register discovered provider classes
        self.__discoverProviders(
            modules=providers_modules,
        )

        # Load and register core framework providers
        self.__loadCoreProviders()

    def __resolveEagerProvider(self) -> None:
        """
        Resolve and register all eager service providers.

        Parameters
        ----------
        self : Application
            The current Application instance.

        Returns
        -------
        None
            This method registers eager providers and schedules their boot
            methods if asynchronous.
        """
        from orionis.services.introspection.modules.engine import ModuleEngine
        eager_providers: dict = self.__bootstrap.get("providers", {}).get("eager", {})

        # Iterate and resolve each eager provider class
        for full_path_provider, provider_info in eager_providers.items():

            # Skip if this provider has already been resolved to prevent duplicates
            if full_path_provider in self.__cache_resolved_providers:
                continue

            # Resolve the provider class using the module engine and register it
            provider: type[IServiceProvider] = ModuleEngine.resolveClass(
                metadata=provider_info,
            )
            instance = provider(self)
            self.__registerEagerProviders(instance)

            # Schedule boot for async providers, call directly for sync
            if hasattr(instance, "boot") and callable(instance.boot):
                if asyncio.iscoroutinefunction(instance.boot):
                    self.__pending_boot_providers.append(instance)
                else:
                    instance.boot()

            # Add to resolved providers cache to prevent duplicate resolution
            self.__cache_resolved_providers.add(full_path_provider)

    def __registerEagerProviders(
        self,
        provider: IServiceProvider,
    ) -> None:
        """
        Register the given service provider instance.

        Parameters
        ----------
        provider : IServiceProvider
            The service provider instance to register.

        Returns
        -------
        None
            This method calls the provider's register method if it exists.
        """
        if hasattr(provider, "register") and callable(provider.register):
            provider.register()

    async def __bootEagerProviders(self) -> None:
        """
        Boot all pending eager service providers.

        Schedule the asynchronous boot methods of all pending eager service
        providers using the current event loop.

        Returns
        -------
        None
            This method does not return a value.
        """
        # Return immediately if there are no pending eager providers.
        if not self.__pending_boot_providers:
            return

        # Boot each pending eager provider instance asynchronously.
        while self.__pending_boot_providers:
            provider = self.__pending_boot_providers.pop()
            await provider.boot()

    # --- Routing Configuration and Validation ---

    def withRouting(
        self,
        api: Path | list[Path] | None = None,
        web: Path | list[Path] | None = None,
        console: Path | list[Path] | None = None,
        health: str | None = None,
    ) -> Self:
        """
        Configure routing paths for the application.

        Parameters
        ----------
        api : Path | list[Path] | None
            Path or list of Paths for API routing.
        web : Path | list[Path] | None
            Path or list of Paths for web routing.
        console : Path | list[Path] | None
            Path or list of Paths for console routing.
        health : str | None
            Health check route as a string.

        Returns
        -------
        Application
            The current Application instance for method chaining.

        Raises
        ------
        ValueError
            If all routing arguments are None.
        TypeError
            If any argument is not of the expected type.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Validate that at least one routing path is provided
        if all(route is None for route in (api, web, console, health)):
            error_msg = (
                "At least one routing path must be provided."
            )
            raise ValueError(error_msg)

        # Validate types of routing arguments
        self.__validateRoutingArgument(api, "api")
        self.__validateRoutingArgument(web, "web")
        self.__validateRoutingArgument(console, "console")

        # Validate health route type
        if health is not None and not isinstance(health, str):
            error_msg = (
                f"Expected str for 'health' routing, got {type(health).__name__}."
            )
            raise TypeError(error_msg)

        # Store routing configuration
        self.__bootstrap["routing"] = {
            "api": api,
            "web": web,
            "console": console,
            "health": health,
        }

        # Return self instance for method chaining
        return self

    def __ensureRoutingDefinition(
        self,
        path: Path,
    ) -> None:
        """
        Ensure the file contains valid routing definitions.

        Parameters
        ----------
        path : Path
            File path to check for routing definitions.

        Returns
        -------
        None
            This method raises if the file does not contain valid routing
            definitions.

        Raises
        ------
        TypeError
            If the file does not contain valid routing definitions.
        """
        # Import the module engine for introspection
        from orionis.services.introspection.modules.engine import ModuleEngine

        # Check for required routing imports in the file
        required_imports = {
            "orionis.support.facades.reactor",
            "orionis.support.facades.router",
        }

        # Validate that the file contains routing definitions
        if not ModuleEngine.containsImports(path, required_imports):
            error_msg = (
                f"The file '{path}' does not contain valid routing definitions."
            )
            raise TypeError(error_msg)

    def __validateRoutingArgument(
        self,
        arg: Path | list[Path] | None,
        name: str,
    ) -> None:
        """
        Validate routing argument type and ensure routing definition.

        Parameters
        ----------
        arg : Path | list[Path] | None
            The routing argument to validate.
        name : str
            The name of the routing argument for error reporting.

        Returns
        -------
        None
            Raises TypeError if validation fails.

        Notes
        -----
        Ensures that the argument is either a Path or a list of Paths and that
        each Path contains a valid routing definition.
        """
        # Validate argument type and routing definition recursively for lists
        if arg is not None:
            if isinstance(arg, list):
                for route in arg:
                    self.__validateRoutingArgument(route, name)
            elif isinstance(arg, Path):
                self.__ensureRoutingDefinition(arg)
            else:
                error_msg = (
                    f"Expected Path or list[Path] for '{name}' routing, got "
                    f"{type(arg).__name__}."
                )
                raise TypeError(error_msg)

    # --- Exception Handler Configuration ---

    def withExceptionHandler(
        self,
        handler: type[IBaseExceptionHandler],
    ) -> Self:
        """
        Register a custom exception handler class for the application.

        Allow specification of a custom exception handler class that inherits from
        BaseExceptionHandler. The handler class manages exceptions raised within
        the application, including reporting and rendering error messages. The
        provided handler must be a class (not an instance) and must inherit from
        BaseExceptionHandler.

        Parameters
        ----------
        handler : Type[IBaseExceptionHandler]
            The exception handler class to be used by the application. Must be a
            subclass of BaseExceptionHandler.

        Returns
        -------
        Application
            The current Application instance, allowing for method chaining.

        Raises
        ------
        TypeError
            If the provided handler is not a class or is not a subclass of
            BaseExceptionHandler.
        RuntimeError
            If attempting to set handler after application has been booted.
        ValueError
            If handler has already been set and cannot be modified.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Ensure the provided handler is a class type
        if not isinstance(handler, type):
            error_msg = (
                f"Expected exception handler class, got {type(handler).__name__}"
            )
            raise TypeError(error_msg)

        # Ensure the provided handler is a subclass of BaseExceptionHandler
        if not issubclass(handler, IBaseExceptionHandler):
            error_msg = (
                f"Expected BaseExceptionHandler subclass, got {type(handler).__name__}"
            )
            raise TypeError(error_msg)

        # Store the exception handler class for later instantiation
        self.__bootstrap["exception_handler"] = {
            "module": handler.__module__,
            "class": handler.__name__,
        }

        # Return the application instance for method chaining
        return self

    async def getExceptionHandler(
        self,
    ) -> IBaseExceptionHandler:
        """
        Return the registered exception handler instance.

        Retrieve an instance of the exception handler set via `setExceptionHandler`.
        If no custom handler is set, return a default `BaseExceptionHandler` instance.
        This object manages exception reporting and rendering within the application.

        Returns
        -------
        IBaseExceptionHandler
            Instance of the registered exception handler. If none is set, returns
            a default `BaseExceptionHandler` instance.

        Raises
        ------
        RuntimeError
            If called before the application is booted.
        """
        # Ensure the application is booted before accessing the exception handler
        if not self.__booted:
            error_msg = (
                "Cannot retrieve exception handler before application is booted."
            )
            raise RuntimeError(error_msg)

        # Lazy import
        from orionis.services.introspection.modules.engine import ModuleEngine

        # Resolve and cache the exception handler instance if not already done
        if self.__exception_handler_resolved is None:
            self.__exception_handler_resolved = ModuleEngine.resolveClass(
                metadata=self.__bootstrap["exception_handler"],
            )

        # Return the exception handler instance
        return await self.build(self.__exception_handler_resolved)

    # --- Scheduler Configuration ---

    def withScheduler(
        self,
        scheduler: type[IBaseScheduler],
    ) -> Self:
        """
        Register a custom scheduler class for the application.

        This method allows you to specify a custom scheduler class that inherits
        from `BaseScheduler`. The scheduler is responsible for managing scheduled
        tasks within the application. The provided class will be validated to
        ensure it is a subclass of `BaseScheduler` and then stored for later use.

        Parameters
        ----------
        scheduler : Type[IBaseScheduler]
            The scheduler class to be used by the application. Must inherit from
            `BaseScheduler`.

        Returns
        -------
        Application
            The current `Application` instance to enable method chaining.

        Raises
        ------
        RuntimeError
            If attempting to set scheduler after application has been booted.
        ValueError
            If scheduler has already been set and cannot be modified.
        TypeError
            If the provided scheduler is not a subclass of `BaseScheduler`.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Validate that the scheduler is a subclass of BaseScheduler
        if not issubclass(scheduler, IBaseScheduler):
            error_msg = (
                f"Expected BaseScheduler subclass, got {type(scheduler).__name__}"
            )
            raise TypeError(error_msg)

        # Store the scheduler class for later instantiation
        self.__bootstrap["scheduler"] = {
            "module": scheduler.__module__,
            "class": scheduler.__name__,
        }

        # Return the application instance for method chaining
        return self

    async def getScheduler(
        self,
    ) -> IBaseScheduler:
        """
        Return the currently registered scheduler instance.

        Returns
        -------
        IBaseScheduler
            The registered scheduler instance.

        Raises
        ------
        RuntimeError
            If the application is not booted.
        """
        # Ensure the application is booted before accessing the scheduler
        if not self.__booted:
            error_msg = "Cannot retrieve scheduler before application is booted."
            raise RuntimeError(error_msg)

        # Lazy import
        from orionis.services.introspection.modules.engine import ModuleEngine

        # Resolve and cache the scheduler instance if not already done
        if self.__scheduler_resolved is None:
            self.__scheduler_resolved = ModuleEngine.resolveClass(
                metadata=self.__bootstrap["scheduler"],
            )

        # Return the scheduler instance
        return await self.build(self.__scheduler_resolved)

    # --- Configuration Subsystem Setup Methods ---

    def withConfigApp(
        self,
        **app_config: dict,
    ) -> Self:
        """
        Configure the application using keyword arguments.

        This method provides a convenient way to set application configuration
        by passing individual configuration parameters as keyword arguments.
        The parameters are used to create an App configuration instance.

        Parameters
        ----------
        **app_config : dict
            Configuration parameters for the application. These must match the
            field names and types expected by the App dataclass from
            orionis.foundation.config.app.entities.app.App.

        Returns
        -------
        Application
            The current application instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided application configuration
        self.__bootstrap["config"]["app"] = app_config

        # Return the application instance for method chaining
        return self

    def withConfigAuth(
        self,
        **auth_config: dict,
    ) -> Self:
        """
        Configure the authentication subsystem using keyword arguments.

        This method allows you to set authentication configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct an `Auth` configuration instance,
        which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **auth_config : dict
            Keyword arguments representing authentication configuration options.
            These must match the field names and types expected by the `Auth` dataclass
            from `orionis.foundation.config.auth.entities.auth.Auth`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided authentication configuration
        self.__bootstrap["config"]["auth"] = auth_config

        # Return the application instance for method chaining
        return self

    def withConfigCache(
        self,
        **cache_config: dict,
    ) -> Self:
        """
        Configure the cache subsystem using keyword arguments.

        This method allows you to set cache configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Cache` configuration instance,
        which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **cache_config : dict
            Keyword arguments representing cache configuration options.
            These must match the field names and types expected by the `Cache` dataclass
            from `orionis.foundation.config.cache.entities.cache.Cache`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided cache configuration
        self.__bootstrap["config"]["cache"] = cache_config

        # Return the application instance for method chaining
        return self

    def withConfigCors(
        self,
        **cors_config: dict,
    ) -> Self:
        """
        Configure the CORS subsystem using keyword arguments.

        This method allows you to set CORS configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Cors` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **cors_config : dict
            Keyword arguments representing CORS configuration options.
            These must match the field names and types expected by the `Cors` dataclass
            from `orionis.foundation.config.cors.entities.cors.Cors`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided CORS configuration
        self.__bootstrap["config"]["cors"] = cors_config

        # Return the application instance for method chaining
        return self

    def withConfigDatabase(
        self,
        **database_config: dict,
    ) -> Self:
        """
        Configure the database subsystem using keyword arguments.

        This method allows you to set database configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Database` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **database_config : dict
            Keyword arguments representing database configuration options.
            These must match the field names and types expected by the `Database`
            dataclass from
                `orionis.foundation.config.database.entities.database.Database`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided database configuration
        self.__bootstrap["config"]["database"] = database_config

        # Return the application instance for method chaining
        return self

    def withConfigFilesystems(
        self,
        **filesystems_config: dict,
    ) -> Self:
        """
        Configure the filesystems subsystem using keyword arguments.

        This method allows you to set filesystems configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Filesystems` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **filesystems_config : dict
            Keyword arguments representing filesystems configuration options.
            These must match the field names and types expected by the `Filesystems`
            dataclass from:
              `orionis.foundation.config.filesystems.entitites.filesystems.Filesystems`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided filesystems configuration
        self.__bootstrap["config"]["filesystems"] = filesystems_config

        # Return the application instance for method chaining
        return self

    def withConfigLogging(
        self,
        **logging_config: dict,
    ) -> Self:
        """
        Configure the logging subsystem using keyword arguments.

        This method allows you to set logging configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Logging` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **logging_config : dict
            Keyword arguments representing logging configuration options.
            These must match the field names and types expected by the `Logging`
            dataclass from `orionis.foundation.config.logging.entities.logging.Logging`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided logging configuration
        self.__bootstrap["config"]["logging"] = logging_config

        # Return the application instance for method chaining
        return self

    def withConfigMail(
        self,
        **mail_config: dict,
    ) -> Self:
        """
        Configure the mail subsystem using keyword arguments.

        This method allows you to set mail configuration for the application
        by passing individual configuration parameters as keyword arguments. The
        provided parameters are used to construct a `Mail` configuration instance,
        which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **mail_config : dict
            Keyword arguments representing mail configuration options.
            These must match the field names and types expected by the `Mail` dataclass
            from `orionis.foundation.config.mail.entities.mail.Mail`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided mail configuration
        self.__bootstrap["config"]["mail"] = mail_config

        # Return the application instance for method chaining
        return self

    def withConfigQueue(
        self,
        **queue_config: dict,
    ) -> Self:
        """
        Configure the queue subsystem using keyword arguments.

        This method allows you to set queue configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Queue` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **queue_config : dict
            Keyword arguments representing queue configuration options.
            These must match the field names and types expected by the `Queue` dataclass
            from `orionis.foundation.config.queue.entities.queue.Queue`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided queue configuration
        self.__bootstrap["config"]["queue"] = queue_config

        # Return the application instance for method chaining
        return self

    def withConfigSession(
        self,
        **session_config: dict,
    ) -> Self:
        """
        Configure the session subsystem using keyword arguments.

        This method allows you to set session configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Session` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **session_config : dict
            Keyword arguments representing session configuration options.
            These must match the field names and types expected by the `Session`
            dataclass from `orionis.foundation.config.session.entities.session.Session`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided session configuration
        self.__bootstrap["config"]["session"] = session_config

        # Return the application instance for method chaining
        return self

    def withConfigTesting(
        self,
        **testing_config: dict,
    ) -> Self:
        """
        Configure the testing subsystem using keyword arguments.

        This method allows you to set testing configuration for the application
        by passing individual configuration parameters as keyword arguments.
        The provided parameters are used to construct a `Testing` configuration
        instance, which is then loaded into the application's internal configurators.

        Parameters
        ----------
        **testing_config : dict
            Keyword arguments representing testing configuration options.
            These must match the field names and types expected by the `Testing`
            dataclass from `orionis.foundation.config.testing.entities.testing.Testing`.

        Returns
        -------
        Application
            Returns the current `Application` instance to enable method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Store the provided testing configuration
        self.__bootstrap["config"]["testing"] = testing_config

        # Return the application instance for method chaining
        return self

    def withConfigPaths(
        self,
        **paths: dict[str, str | Path | None],
    ) -> Self:
        """
        Set and resolve application directory paths with optimized performance.

        Parameters
        ----------
        root : str | Path | None, optional
            Root directory path.
        app : str | Path | None, optional
            Application directory path.
        console : str | Path | None, optional
            Console directory path.
        exceptions : str | Path | None, optional
            Exceptions directory path.
        http : str | Path | None, optional
            HTTP directory path.
        models : str | Path | None, optional
            Models directory path.
        providers : str | Path | None, optional
            Providers directory path.
        notifications : str | Path | None, optional
            Notifications directory path.
        services : str | Path | None, optional
            Services directory path.
        jobs : str | Path | None, optional
            Jobs directory path.
        bootstrap : str | Path | None, optional
            Bootstrap directory path.
        config : str | Path | None, optional
            Config directory path.
        database : str | Path | None, optional
            Database directory path.
        resources : str | Path | None, optional
            Resources directory path.
        routes : str | Path | None, optional
            Routes directory path.
        storage : str | Path | None, optional
            Storage directory path.
        tests : str | Path | None, optional
            Tests directory path.

        Returns
        -------
        Application
            The current Application instance for method chaining.
        """
        # Return early if already cached
        if self.__cached:
            return self

        # Ensure configuration is not locked
        self.__assertConfigMutable()

        # Lazy import and deep freeze core paths
        from orionis.foundation.core_paths import CORE_APP_PATHS
        from orionis.support.structures.freezer import FreezeThaw

        # Deep unfreeze core application paths for mutability
        core_app_paths = FreezeThaw.thaw(CORE_APP_PATHS)

        # Get app root once and cache it
        app_root = Path.cwd().resolve()

        # Path validation function for performance
        def is_valid_path(path_arg: type[Any]) -> bool:
            """
            Check if the provided argument is a valid path type.

            Parameters
            ----------
            path_arg : type[Any]
                The argument to validate as a path type.

            Returns
            -------
            bool
                True if the argument is a valid path (str or Path), False otherwise.
            """
            return path_arg is not None and isinstance(path_arg, (str, Path))

        # Define default path mappings for performance
        default_paths = {"root": app_root, **core_app_paths}

        # Collect all arguments in a dictionary for batch processing
        path_args = {
            "root": paths.get("root"),
            "app": paths.get("app"),
            "console": paths.get("console"),
            "exceptions": paths.get("exceptions"),
            "http": paths.get("http"),
            "models": paths.get("models"),
            "providers": paths.get("providers"),
            "notifications": paths.get("notifications"),
            "services": paths.get("services"),
            "jobs": paths.get("jobs"),
            "bootstrap": paths.get("bootstrap"),
            "config": paths.get("config"),
            "database": paths.get("database"),
            "resources": paths.get("resources"),
            "routes": paths.get("routes"),
            "storage": paths.get("storage"),
            "tests": paths.get("tests"),
        }

        # Build final paths dictionary efficiently
        final_paths = {}
        for key, value in path_args.items():
            if is_valid_path(value):
                # Use provided path (convert to Path object and resolve)
                final_paths[key] = Path(value).resolve()
            # Use default path
            elif key == "root":
                final_paths[key] = default_paths[key]
            else:
                # Resolve default relative path as Path object
                final_paths[key] = (app_root / default_paths[key]).resolve()

        # Store the resolved paths in the application configuration
        self.__bootstrap["paths"] = final_paths

        # Return self for method chaining
        return self

    # --- Configuration Loading Methods ---

    def __loadCustomConfig(
        self,
        default_config: dict[str, Any],
        custom_config: dict[str, Any],
        dataclasses: set[tuple[str, str, str, type[Any]]] | None = None,
    ) -> dict[str, Any]:
        """
        Merge custom configuration and dataclass defaults into the base config.

        Parameters
        ----------
        default_config : dict[str, Any]
            The base configuration dictionary containing default values.
        custom_config : dict[str, Any]
            The custom configuration dictionary to merge into defaults.
        dataclasses : set[tuple[str, str, str, Type[Any]]] | None, optional
            Set of tuples containing dataclass info to merge, or None.

        Returns
        -------
        dict[str, Any]
            The merged configuration dictionary containing all sections.
        """
        # Lazy import
        from dataclasses import asdict

        # Helper function to update a config section
        def update_section(
            section: str,
            values: dict[str, Any],
            base: dict[str, Any],
        ) -> None:
            # Merge values into the base config section
            if section in base and isinstance(base[section], dict):
                base[section].update(values)
            else:
                base[section] = values

        # Merge custom config sections into defaults
        for section, values in custom_config.items():
            if isinstance(values, dict):
                update_section(section, values, default_config)

        # Merge dataclass config sections into defaults
        if dataclasses:
            for section, _, _, cls in dataclasses:
                try:
                    update_section(section, asdict(cls()), default_config)
                except Exception as e:
                    error_msg = str(e)
                    raise RuntimeError(error_msg) from e

        # Return merged configuration dictionary
        return default_config

    def __loadConfig(
        self,
    ) -> None:
        """
        Load and merge final configuration from discovered dataclasses & custom config.

        Discovers configuration modules and dataclasses, loads default configuration
        values, merges them with custom configuration, and updates the application's
        bootstrap dictionary with the final configuration and discovered providers.

        Returns
        -------
        None
            This method updates the internal bootstrap configuration in place.
        """
        # Lazy import
        from orionis.foundation.core_config import CORE_CONFIG
        from orionis.support.structures.freezer import FreezeThaw
        from orionis.services.introspection.modules.engine import ModuleEngine
        from copy import deepcopy

        # Deep freeze core configuration for processing
        core_config = FreezeThaw.thaw(CORE_CONFIG)

        # Discover configuration modules in the config directory
        config_paths = self.__bootstrap["paths"]
        config_modules = ModuleEngine.scan(
            app_root=config_paths["root"],
            tarjet_path=config_paths["config"],
        )

        # Discover final dataclasses in the discovered modules
        config_dataclasses = (
            ModuleEngine.discoverFinalDataclasses(
                modules=config_modules,
            )
        )

        # Load default configuration values from built-in dataclasses
        default_config = core_config

        # Retrieve custom configuration values if provided
        custom_config = {}
        if "config" in self.__bootstrap:
            custom_config = deepcopy(self.__bootstrap["config"])

        # Merge custom configuration and dataclass defaults into the base config
        final_config = self.__loadCustomConfig(
            default_config=default_config,
            custom_config=custom_config,
            dataclasses=config_dataclasses,
        )

        # Update the bootstrap configuration with the final merged config
        self.__bootstrap["config"] = final_config

    def __commitConfig(
        self,
    ) -> None:
        """
        Lock configuration and mark application as initialized.

        Freeze the bootstrap configuration to prevent further modifications and
        set the configured flag to indicate the application is ready for use.

        Returns
        -------
        None
            This method does not return a value. It modifies internal state
            to lock configuration.
        """
        # Deep freeze the configuration to prevent further modifications
        self.__lockConfig()

        # Mark configuration as initialized
        self.__configured = True

    # --- Bootstrap Application Methods ---

    def __load(
        self,
    ) -> None:
        """
        Load and initialize the application configuration and providers.

        This method ensures the bootstrap configuration is initialized, sets up
        default paths, loads the final application configuration, loads service
        providers, saves the configuration to cache, and locks the configuration.
        It then registers and boots all service providers.

        Returns
        -------
        None
            This method does not return a value. It modifies internal state.
        """
        # Skip loading if already cached
        if not self.__cached:

            # Ensure bootstrap configuration is initialized
            self.__ensureDefaultBootstrap()

            # Ensure default application paths are set
            self.__ensureDefaultPaths()

            # Load the final application configuration
            self.__loadConfig()

            # Load all service providers
            self.__loadProviders()

            # Save configuration to cache if enabled
            self.__saveCache()

            # Lock and commit the configuration
            self.__commitConfig()

        # Register and boot all service providers
        self.__resolveEagerProvider()

    def create(
        self,
    ) -> Self:
        """
        Bootstrap and initialize the complete application framework.

        Create and configure the application instance by registering it in the
        container, loading all configurations, and marking it as booted.

        Returns
        -------
        Self
            The current Application instance for method chaining.
        """
        # Check if already booted to prevent duplicate initialization
        if not self.__booted:

            # Store the file path where the application was started.
            self.__entry_point = sys._getframe(1).f_code.co_filename

            # Register application instance in the container
            self.instance(IApplication, self)

            # Load and initialize all application components
            self.__load()

            # Set timezone and locale based on configuration
            self.__setTimezoneAndLocale()

            # Mark application as fully booted
            self.__booted = True

        # Return the application instance for method chaining
        return self

    def __setTimezoneAndLocale(
        self,
    ) -> None:
        """
        Configure timezone and locale based on application settings.

        Set system timezone and locale using application configuration values
        with minimal overhead to avoid startup latency. Only performs essential
        operations when configuration values are present.

        Returns
        -------
        None
            This method modifies environment variables and system locale settings
            in place.
        """
        # Extract timezone and locale from application configuration
        app_cfg: dict = self.__bootstrap.get("config", {}).get("app")
        if not app_cfg:
            return

        # Get timezone and locale settings
        tz = app_cfg.get("timezone")
        lc = app_cfg.get("locale")

        # Skip if no timezone/locale configured
        if not tz and not lc:
            return

        # Batch all imports at once
        from contextlib import suppress
        from orionis.support.time.local import LocalDateTime
        import os

        # Load local date-time configuration
        LocalDateTime.loadConfig(timezone_name=tz, locale=lc)

        # Update environment variables
        os.environ.update({
            "TZ": tz,
            "LC_ALL": lc,
            "LANG": lc,
        })

        # Only set timezone if configured and tzset available
        import time
        if hasattr(time, "tzset"):
            time.tzset()

        # Only set locale if configured and not empty
        import locale
        with suppress(locale.Error):
            locale.setlocale(locale.LC_ALL, lc)

    # --- CLI Kernel Handling Method ---

    async def handleCommand(
        self,
        args: list[str] | None = None,
    ) -> int:
        """
        Handle a CLI command using the configured KernelCLI.

        Parameters
        ----------
        args : list[str] | None, optional
            Arguments to pass to the kernel's handle method. Defaults to an empty
            list if not provided.

        Returns
        -------
        int
            The exit code returned by the CLI kernel's handle method.

        Raises
        ------
        RuntimeError
            If KernelCLI is not configured in the application.
        TypeError
            If the CLI kernel does not have a handle method.
        """
        # Initialize CLI kernel if not already cached
        if not self.__kernel_cli:

            # Try to retrieve CLI kernel configuration from bootstrap
            try:
                kernel_metadata = self.__bootstrap["kernels"]["KernelCLI"]
            except KeyError:
                error_msg = "CLI Kernel is not configured in the application."
                raise RuntimeError(error_msg) from None

            # Instantiate the kernel class using configuration
            from orionis.services.introspection.modules.engine import ModuleEngine
            kernel_cls = ModuleEngine.resolveClass(metadata=kernel_metadata)

            # Boot the kernel instance
            kernel_instance: IKernelCLI = kernel_cls()
            await kernel_instance.boot(self)
            self.__kernel_cli = kernel_instance.handle

            # Trigger startup lifecycle event before command execution
            await self.__onStartup(runtime="cli")

        # Execute the kernel's handle method with provided arguments
        response = await self.__kernel_cli(args or [])

        # Trigger shutdown lifecycle event after command execution
        await self.__onShutdown(runtime="cli")

        # Return the response code from the CLI kernel
        return response

    # --- HTTP RSGI/ASGI Kernels Handling Method ---

    async def handleRSGI(
        self,
        scope: object,
        protocol: object,
    ) -> object:
        """
        Handle HTTP requests using the configured KernelHTTP in RSGI mode.

        Parameters
        ----------
        scope : object
            The connection scope information for the RSGI protocol.
        protocol : object
            The protocol instance for the connection.

        Returns
        -------
        object
            The result returned by the HTTP kernel's handleRSGI method.

        Raises
        ------
        RuntimeError
            If KernelHTTP is not configured in the application.
        TypeError
            If the HTTP kernel does not have a handleRSGI method.
        """
        # Initialize HTTP kernel if not already cached
        if not self.__kernel_http_rsgi:

            # Set the application interface type in configuration for kernel resolution
            self.config("app.interface", "rsgi")

            # Lazy import to avoid unnecessary overhead during application startup
            from orionis.services.introspection.modules.engine import ModuleEngine
            from orionis.http.contracts.kernel import IKernelHTTP

            # Retrieve HTTP kernel configuration from bootstrap
            kernel_metadata = self.__bootstrap["kernels"]["KernelHTTP"]

            # Instantiate the kernel class using configuration
            kernel_http = ModuleEngine.resolveClass(metadata=kernel_metadata)

            # Boot the kernel instance and cache the handle method for future calls
            kernel_instance: IKernelHTTP = await self.build(kernel_http)

            # Store the kernel's handle method for RSGI protocol
            self.__kernel_http_rsgi = kernel_instance.handleRSGI

        # Execute the kernel's handle method with provided arguments
        return await self.__kernel_http_rsgi(scope, protocol)

    async def handleASGI(
        self,
        scope: object,
        receive: object,
        send: object,
    ) -> object:
        """
        Handle HTTP requests using the configured KernelHTTP in ASGI mode.

        Parameters
        ----------
        scope : object
            The ASGI connection scope.
        receive : object
            The ASGI receive callable.
        send : object
            The ASGI send callable.

        Returns
        -------
        object
            The result returned by the HTTP kernel's handleASGI method.

        Raises
        ------
        RuntimeError
            If KernelHTTP is not configured in the application.
        TypeError
            If the HTTP kernel does not have a handleASGI method.
        """
        # Initialize HTTP kernel if not already cached
        if not self.__kernel_http_asgi:

            # Set the application interface type in configuration for kernel resolution
            self.config("app.interface", "asgi")

            # Try to retrieve HTTP kernel configuration from bootstrap
            try:
                kernel_metadata = self.__bootstrap["kernels"]["KernelHTTP"]
            except KeyError:
                error_msg = (
                    "HTTP Kernel is not configured in the application."
                )
                raise RuntimeError(error_msg) from None

            # Instantiate the kernel class using configuration
            from orionis.services.introspection.modules.engine import ModuleEngine
            kernel_http = ModuleEngine.resolveClass(metadata=kernel_metadata)
            kernel_instance = await self.build(kernel_http)

            # Validate that the kernel has a callable handleASGI method
            handle_asgi = getattr(kernel_instance, "handleASGI", None)
            if not callable(handle_asgi):
                error_msg = (
                    "The HTTP kernel does not have a handleASGI method."
                )
                raise TypeError(error_msg)

            # Cache the kernel handle method for future calls
            self.__kernel_http_asgi = handle_asgi

        # Execute the kernel's handle method with provided arguments
        return await self.__kernel_http_asgi(scope, receive, send)

    # --- Runtime Configuration Access Methods ---

    def config(
        self,
        key: str | None = None,
        value: object = _SENTINEL,
    ) -> object:
        """
        Get or set application configuration values using dot notation.

        Parameters
        ----------
        key : str | None, optional
            Dot-notated key specifying the configuration value to get or set.
            If None and value is not provided, returns the entire configuration.
        value : Any, optional
            Value to set at the specified key. If not provided, retrieves the value.

        Returns
        -------
        Any
            The configuration value for the given key, or the entire configuration
            if no key is provided. If setting a value, returns the value set.

        Raises
        ------
        RuntimeError
            If the application configuration is not initialized.
        ValueError
            If the configuration key is not a string.
        """
        # Ensure configuration is initialized before accessing or modifying it
        if not self.__configured:
            error_msg = (
                "Application configuration is not initialized."
                "Please call create() first."
            )
            raise RuntimeError(error_msg)

        # Reset the runtime configuration to a mutable copy of the bootstrap config
        if not self.__runtime_config:
            self.resetRuntimeConfig()

        # Return the entire configuration if no key or value is provided
        if key is None and value is _SENTINEL:
            return self.__runtime_config

        # Ensure the key is a string
        if not isinstance(key, str):
            error_msg = "Configuration key must be a string."
            raise TypeError(error_msg)

        # Split the key into parts for nested access
        key_parts: list[str] = key.split(".")

        # If value is not provided, retrieve the configuration value
        if value is _SENTINEL:
            return self.__getRuntimeConfigValue(key_parts)

        # Otherwise, set the configuration value and return it
        return self.__setRuntimeConfigValue(key_parts, value)

    def resetRuntimeConfig(self) -> bool:
        """
        Reset the runtime configuration to a mutable copy of the bootstrap config.

        Reset the application's runtime configuration to a mutable copy of the
        bootstrap configuration. Marks the application as unconfigured, allowing
        re-initialization by calling `create()` again. Useful for testing or
        dynamic configuration reloads.

        Returns
        -------
        bool
            True if the configuration was reset successfully.
        """
        from copy import deepcopy
        from orionis.support.structures.freezer import FreezeThaw

        # Obtain current bootstrap configuration
        bootstrap_config = self.__bootstrap.get("config", {})

        # Deepcopy and unfreeze to ensure mutability and isolation
        self.__runtime_config = FreezeThaw.thaw(deepcopy(bootstrap_config))

        # Return True to indicate successful reset
        return True

    def __getRuntimeConfigValue(
        self,
        key_parts: list[str],
    ) -> object:
        """
        Retrieve a value from a nested dictionary using dot notation.

        Parameters
        ----------
        key_parts : list[str]
            List of keys representing the path in the nested dictionary.

        Returns
        -------
        Any
            The value found at the nested key path, or None if not found.
        """
        cfg = self.__runtime_config
        for part in key_parts:
            if isinstance(cfg, dict) and part in cfg:
                cfg = cfg[part]
            else:
                return None
        return cfg

    def __setRuntimeConfigValue(
        self,
        key_parts: list[str],
        value: object,
    ) -> object:
        """
        Set a value in a nested dictionary using dot notation.

        Parameters
        ----------
        key_parts : list[str]
            List of keys representing the path in the nested dictionary.
        value : Any
            The value to set at the specified nested key path.

        Returns
        -------
        Any
            The value that was set.
        """
        current = self.__runtime_config
        for part in key_parts[:-1]:
            if part not in current or not isinstance(current[part], dict):
                current[part] = {}
            current = current[part]
        current[key_parts[-1]] = value
        return value

    # --- Application Path Access Method ---

    def path(
        self,
        key: str | None = None,
    ) -> Path | dict | None:
        """
        Retrieve an application path configuration value.

        Parameters
        ----------
        key : str | None, optional
            The key for the desired path. If None, returns all paths.

        Returns
        -------
        Path | dict | None
            The resolved path for the given key, all paths as a dictionary,
            or None if the key does not exist.

        Raises
        ------
        RuntimeError
            If the application configuration is not initialized.
        ValueError
            If the key is not a string.
        """
        # Ensure configuration is initialized before accessing paths
        if not self.__configured:
            error_msg = (
                "Application configuration is not initialized. "
                "Please call create() first."
            )
            raise RuntimeError(error_msg)

        # Retrieve the paths configuration
        paths: dict = self.__bootstrap.get("paths", {})

        # Return all paths if no key is provided
        if key is None:
            return paths

        # Validate key type
        if not isinstance(key, str):
            error_msg = (
                "Key must be a string. Use path() without arguments to get all paths."
            )
            raise TypeError(error_msg)

        # Return the requested path or None if not found
        return paths.get(key)

    def routingPaths(
        self,
        key: str | None = None,
    ) -> list[Path] | dict | Path | None:
        """
        Return routing file paths from application configuration.

        Retrieve routing file paths configured for the application. Return paths
        for a specific routing type if key is provided, otherwise return the
        complete routing configuration dictionary.

        Parameters
        ----------
        key : str | None, optional
            The routing type to retrieve ('api', 'web', 'console', or 'health').
            If None, returns the complete routing configuration.

        Returns
        -------
        list[Path] | dict | Path | None
            List of Path objects for the specified routing type, complete routing
            configuration dictionary if no key is provided, single Path for health
            routes, or None if the key does not exist.

        Raises
        ------
        RuntimeError
            If the application configuration is not initialized.
        TypeError
            If the key is not a string or None.
        """
        # Ensure configuration is initialized before accessing routing
        if not self.__configured:
            error_msg = (
                "Application configuration is not initialized. "
                "Please call create() before accessing routing paths."
            )
            raise RuntimeError(error_msg)

        # Validate key type if provided
        if key is not None and not isinstance(key, str):
            error_msg = (
                "Routing key must be a string or None. "
                f"Got {type(key).__name__}"
            )
            raise TypeError(error_msg)

        # Retrieve the routing configuration from bootstrap
        routing: dict = self.__bootstrap.get("routing", {})

        # Return complete routing configuration if no key specified
        if key is None:
            return routing

        # Validate key exists in valid routing types
        valid_keys = {"api", "web", "console"}
        if key not in valid_keys:
            return None

        # Return the routing paths for the specified key
        return routing.get(key)

    # --- Environment Check Methods ---

    def isProduction(
        self,
    ) -> bool:
        """
        Check if the application is running in a production environment.

        Check the 'app.env' configuration value to determine if the current
        environment is set to 'production'. This is useful for conditionally
        executing code based on the environment, such as enabling or disabling
        debug features.

        Returns
        -------
        bool
            True if the application environment contains 'prod', False otherwise.

        Raises
        ------
        RuntimeError
            If the application configuration is not initialized.
        """
        # Retrieve the current application environment from configuration
        app_env = self.config("app.env")

        # Ensure the application is booted before accessing configuration
        if app_env is None:
            error_msg = (
                "Application configuration is not initialized. "
                "Please call create() before checking the environment."
            )
            raise RuntimeError(error_msg)

        # Return True if the environment is 'production', otherwise False
        return "prod" in str(app_env).lower()

    def isDebug(
        self,
    ) -> bool:
        """
        Check if the application is running in debug mode.

        Retrieve the 'app.debug' configuration value to determine if debug mode
        is currently enabled for the application.

        Returns
        -------
        bool
            True if debug mode is enabled, False otherwise.

        Raises
        ------
        RuntimeError
            If the application configuration is not initialized.
        """
        # Retrieve the current debug setting from configuration
        app_debug = self.config("app.debug")

        # Raise if configuration is not initialized
        if app_debug is None:
            error_msg = (
                "Application configuration is not initialized. "
                "Please call create() before checking the debug mode."
            )
            raise RuntimeError(error_msg)

        # Return True if debug mode is enabled, otherwise False
        return bool(app_debug)

    def hasWebSockets(
        self,
    ) -> bool:
        """
        Check if WebSockets are configured/enabled in the application.

        Returns
        -------
        bool
            True if WebSockets are enabled/configured, False otherwise.

        Raises
        ------
        RuntimeError
            If the application configuration is not initialized.
        """
        # Example: check config("websockets.enabled")
        if not self.__configured:
            error_msg = (
                "Application configuration is not initialized. "
                "Please call create() before checking WebSockets."
            )
            raise RuntimeError(error_msg)
        return False
