"""
Async main Daisi client providing unified interface to all services.
"""

from typing import Any, Optional

from ..config import DaisiConfig
from .clients.auth import AsyncAuthClient
from .clients.commands import AsyncAppCommandsClient, AsyncHostCommandsClient
from .clients.hosts import AsyncHostClient
from .clients.inference import AsyncInferenceClient
from .clients.models import AsyncModelsClient
from .clients.peers import AsyncPeerClient
from .clients.session import AsyncSessionClient
from .clients.settings import AsyncSettingsClient


class AsyncDaisiClient:
    """Async unified client for interacting with Daisi services.

    This client provides async access to all Daisi services through a single interface.
    It manages the configuration and lifecycle of all underlying async gRPC clients.

    Example:
        >>> async with AsyncDaisiClient(client_key="your-key") as client:
        ...     session_id, host, _ = await client.session.create(model_name="llama-3")
        ...     _, inference_id = await client.inference.create(session_id=session_id)
        ...     async for response in client.inference.send("Hello"):
        ...         print(response.Content, end="")

    Attributes:
        config: Daisi configuration
        auth: Async authentication client
        session: Async session management client
        inference: Async inference client
        models: Async models client
        hosts: Async host management client
        peers: Async peer client
        settings: Async settings client
        host_commands: Async host commands client
        app_commands: Async app commands client
    """

    def __init__(
        self,
        client_key: Optional[str] = None,
        orc_address: Optional[str] = None,
        orc_port: Optional[int] = None,
        use_ssl: bool = True,
    ) -> None:
        """Initialize async Daisi client.

        Args:
            client_key: Client authentication key. Falls back to DAISI_CLIENT_KEY env var.
            orc_address: Orchestrator address. Falls back to DAISI_ORC_ADDRESS env var.
            orc_port: Orchestrator port. Falls back to DAISI_ORC_PORT env var.
            use_ssl: Whether to use SSL/TLS for connections.

        Raises:
            ValueError: If required configuration is missing.
        """
        self.config = DaisiConfig(
            client_key=client_key,
            orc_address=orc_address,
            orc_port=orc_port,
            use_ssl=use_ssl,
        )

        self.auth = AsyncAuthClient(self.config)
        self.session = AsyncSessionClient(self.config)
        self.inference = AsyncInferenceClient(self.config)
        self.models = AsyncModelsClient(self.config)
        self.hosts = AsyncHostClient(self.config)
        self.peers = AsyncPeerClient(self.config)
        self.settings = AsyncSettingsClient(self.config)
        self.host_commands = AsyncHostCommandsClient(self.config)
        self.app_commands = AsyncAppCommandsClient(self.config)

    async def close(self) -> None:
        """Close all async client connections."""
        await self.auth.close()
        await self.session.close()
        await self.inference.close()
        await self.models.close()
        await self.hosts.close()
        await self.peers.close()
        await self.settings.close()
        await self.host_commands.close()
        await self.app_commands.close()

    async def __aenter__(self) -> "AsyncDaisiClient":
        """Async context manager entry."""
        return self

    async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
        """Async context manager exit."""
        await self.close()
