"""Abstract base class for communication strategies."""

from abc import ABC, abstractmethod
from collections.abc import AsyncGenerator, Awaitable, Callable

from digitalkin.services.base_strategy import BaseStrategy


class CommunicationStrategy(BaseStrategy, ABC):
    """Abstract base class for module-to-module communication.

    This service enables:
    - Archetype → Tool communication
    - Archetype → Archetype communication
    - Tool → Tool communication
    - Any module → Any module communication

    The service wraps the Module Service protocol from agentic-mesh-protocol.
    """

    @abstractmethod
    async def cleanup(self) -> None:
        """Clean up communication resources.

        This method should release any held resources such as
        gRPC channels, connection pools, etc.
        """
        raise NotImplementedError

    @abstractmethod
    async def get_module_schemas(
        self,
        module_address: str,
        module_port: int,
        *,
        llm_format: bool = False,
    ) -> dict[str, dict]:
        """Get module schemas (input/output/setup/secret/cost).

        Args:
            module_address: Target module address
            module_port: Target module port
            llm_format: Return LLM-friendly format (simplified schema).
                Note: cost always returns actual data regardless of this flag.

        Returns:
            Dictionary containing schemas:
            {
                "input": {...},
                "output": {...},
                "setup": {...},
                "secret": {...},
                "cost": {...}
            }
        """
        raise NotImplementedError

    @abstractmethod
    async def call_module(
        self,
        module_address: str,
        module_port: int,
        input_data: dict,
        setup_id: str,
        mission_id: str,
        callback: Callable[[dict], Awaitable[None]] | None = None,
        metadata: dict[str, str] | None = None,
    ) -> AsyncGenerator[dict, None]:
        """Call a module and stream responses.

        Uses Module Service StartModule RPC to execute the module.
        Streams responses as they are generated by the module.

        Args:
            module_address: Target module address
            module_port: Target module port
            input_data: Input data as dictionary
            setup_id: Setup configuration ID
            mission_id: Mission context ID
            callback: Optional callback for each response
            metadata: Optional gRPC metadata (headers) to send with the request.

        Yields:
            Streaming responses from module as dictionaries
        """
        # Make this an actual async generator to satisfy type checkers
        if False:  # pragma: no cover
            yield {}
        raise NotImplementedError
