from abc import ABC, abstractmethod
import asyncio

class ITestService(ABC):
    """
    Interface for a test service that provides a method to retrieve a message.

    Methods
    -------
    get_message() : str
        Retrieve a message as a string.

    Returns
    -------
    str
        The message provided by the service.
    """

    @abstractmethod
    def get_message(self) -> str:
        """
        Retrieve a message as a string.

        Returns
        -------
        str
            The message provided by the service.
        """
        pass

class TestService(ITestService):
    """
    Concrete implementation of ITestService for synchronous operations.

    Methods
    -------
    get_message() : str
        Returns a greeting message from the synchronous test service.

    Returns
    -------
    str
        A greeting message from the synchronous service.
    """

    def get_message(self) -> str:
        """
        Returns a greeting message from the synchronous service.

        Returns
        -------
        str
            A greeting message from the synchronous service.
        """
        return "Hello from sync service"

class ITestServiceWithDependency(ABC):
    """
    Interface for a test service that depends on other components.

    Methods
    -------
    get_combined_message() : str
        Returns a combined message from the service and its dependencies.

    Returns
    -------
    str
        The combined message generated by the service and its dependencies.
    """

    @abstractmethod
    def get_combined_message(self) -> str:
        """
        Returns a combined message as a string.

        Returns
        -------
        str
            The combined message generated by the service and its dependencies.
        """
        pass

class TestServiceWithDependency(ITestServiceWithDependency):
    """
    Test service class that depends on another service implementing ITestService.

    This class demonstrates dependency injection by accepting an instance of ITestService
    in its constructor and providing a method to return a combined message.

    Parameters
    ----------
    service : ITestService
        An instance of a service implementing the ITestService interface.

    Methods
    -------
    get_combined_message() : str
        Returns a string that combines a prefix with the message from the injected service.

    Returns
    -------
    str
        The combined message string.
    """

    def __init__(self, service: ITestService):
        """
        Initialize the class with the provided service.

        Parameters
        ----------
        service : ITestService
            An instance of ITestService to be used by this class.
        """
        self.service = service

    def get_combined_message(self) -> str:
        """
        Returns a combined message string by prefixing the message from the service with 'Combined:'.

        Returns
        -------
        str
            The combined message string, prefixed with 'Combined:'.
        """
        return f"Combined: {self.service.get_message()}"

class IAsyncTestService(ABC):
    """
    Abstract base class that defines the interface for an asynchronous test service.

    Methods
    -------
    get_async_message() : str
        Asynchronously retrieves a message as a string.

    Returns
    -------
    str
        The message provided by the asynchronous service.
    """

    @abstractmethod
    async def get_async_message(self) -> str:
        """
        Asynchronously retrieve a message as a string.

        Returns
        -------
        str
            The message provided by the asynchronous service.
        """
        pass

class AsyncTestService(IAsyncTestService):
    """
    Provides asynchronous test operations for demonstration purposes.

    Methods
    -------
    get_async_message() : str
        Asynchronously returns a test message after a short delay.

    Returns
    -------
    str
        A greeting message from the async service.
    """

    async def get_async_message(self) -> str:
        """
        Asynchronously retrieves a message after a short delay.

        Returns
        -------
        str
            A greeting message from the async service.
        """
        # Simulate asynchronous operation with a short delay
        await asyncio.sleep(0.1)
        return "Hello from async service"

class IAsyncTestServiceWithDependency(ABC):
    """
    An abstract base class representing an asynchronous test service with dependencies.
    This interface defines a contract for services that provide a combined asynchronous message,
    potentially aggregating results from dependent services.
    Methods
    -------
    get_combined_async_message() -> str
        Asynchronously retrieves a combined message from the service and its dependencies.
    """

    @abstractmethod
    async def get_combined_async_message(self) -> str:
        """
        Asynchronously retrieves and returns a combined message as a string.

        Returns:
            str: The combined asynchronous message.
        """
        pass

class AsyncTestServiceWithDependency(IAsyncTestServiceWithDependency):
    """
    AsyncTestServiceWithDependency is a service class that depends on another asynchronous test service.

    Parameters
    ----------
    service : IAsyncTestService
        An instance of a service implementing asynchronous message retrieval.

    Methods
    -------
    get_combined_async_message() -> str
        Asynchronously retrieves a message from the dependent service and returns it combined with a prefix.
    """

    def __init__(self, service: IAsyncTestService):
        """
        Initialize the AsyncTestServiceWithDependency with the provided asynchronous test service.

        Parameters
        ----------
        service : IAsyncTestService
            An instance of the asynchronous test service to be used by this class.
        """

        # Store the dependency for later use
        self.service = service

    async def get_combined_async_message(self) -> str:
        """
        Asynchronously retrieve a message from the dependent service and return it combined with a prefix.

        This method awaits the asynchronous message retrieval from the injected service and then
        formats the result by prefixing it with 'Combined: '.

        Returns
        -------
        str
            The combined message in the format "Combined: <message>", where <message> is the result
            from the dependent asynchronous service.
        """

        # Await the asynchronous message from the dependency
        msg = await self.service.get_async_message()

        # Combine the prefix with the retrieved message
        return f"Combined: {msg}"

class MixedService:
    """
    Service that combines both synchronous and asynchronous test services.

    This class demonstrates how to work with both sync and async dependencies,
    providing methods to retrieve messages from each and a combined result.

    Parameters
    ----------
    sync_service : ITestService
        An instance of a synchronous test service.
    async_service : IAsyncTestService
        An instance of an asynchronous test service.
    """

    def __init__(self, sync_service: ITestService, async_service: IAsyncTestService):
        """
        Initialize MixedService with synchronous and asynchronous service dependencies.

        Parameters
        ----------
        sync_service : ITestService
            The synchronous service dependency.
        async_service : IAsyncTestService
            The asynchronous service dependency.
        """
        self.sync_service = sync_service
        self.async_service = async_service

    def get_sync_message(self) -> str:
        """
        Retrieve a message from the synchronous service and prefix it.

        Returns
        -------
        str
            The message from the synchronous service, prefixed with 'Mixed sync:'.
        """

        # Get message from the synchronous service and add a prefix
        return f"Mixed sync: {self.sync_service.get_message()}"

    async def get_async_message(self) -> str:
        """
        Asynchronously retrieve a message from the asynchronous service and prefix it.

        Returns
        -------
        str
            The message from the asynchronous service, prefixed with 'Mixed async:'.
        """

        # Await the message from the asynchronous service and add a prefix
        async_msg = await self.async_service.get_async_message()
        return f"Mixed async: {async_msg}"

    async def get_both_messages(self) -> str:
        """
        Retrieve messages from both the synchronous and asynchronous services and combine them.

        This method fetches the synchronous message and awaits the asynchronous message,
        then returns a formatted string containing both.

        Returns
        -------
        str
            A combined string in the format "Both: sync='<sync_msg>', async='<async_msg>'".
        """

        # Get the synchronous message
        sync_msg = self.sync_service.get_message()

        # Await the asynchronous message
        async_msg = await self.async_service.get_async_message()

        # Combine both messages in a formatted string
        return f"Both: sync='{sync_msg}', async='{async_msg}'"

def sync_callable() -> str:
    """
    Returns a fixed string result from a synchronous callable.

    This function demonstrates a simple synchronous callable that does not take any arguments
    and returns a static string value.

    Returns
    -------
    str
        The result string from the synchronous callable, specifically "Sync callable result".
    """
    # Return a static string result
    return "Sync callable result"

async def async_callable() -> str:
    """
    Asynchronously performs a simulated I/O-bound operation and returns a result string.

    This coroutine simulates an asynchronous operation by awaiting a short delay,
    then returns a static string value.

    Returns
    -------
    str
        The result of the asynchronous operation after a short delay, specifically "Async callable result".
    """
    # Simulate an asynchronous I/O operation with a short delay
    await asyncio.sleep(0.1)
    # Return a static string result
    return "Async callable result"

def sync_callable_with_dependency(service: ITestService) -> str:
    """
    Returns a formatted message using a provided ITestService dependency.

    This synchronous callable accepts an instance of ITestService, retrieves its message,
    and returns a formatted string containing that message.

    Parameters
    ----------
    service : ITestService
        An instance of a service implementing the ITestService interface.

    Returns
    -------
    str
        A string containing the message from the provided service, formatted as
        "Callable with dependency: <service_message>".
    """
    # Retrieve the message from the dependency and format it
    return f"Callable with dependency: {service.get_message()}"

async def async_callable_with_dependency(service: IAsyncTestService) -> str:
    """
    Asynchronously retrieves and formats a message from a provided IAsyncTestService dependency.

    This coroutine awaits the asynchronous message retrieval from the given service,
    then returns a formatted string containing that message.

    Parameters
    ----------
    service : IAsyncTestService
        An instance of a service implementing the asynchronous `get_async_message` method.

    Returns
    -------
    str
        A formatted string containing the message retrieved from the service, in the form
        "Async callable with dependency: <service_message>".
    """

    # Await the asynchronous message from the dependency
    msg = await service.get_async_message()

    # Return the formatted result
    return f"Async callable with dependency: {msg}"