"""
Hosts client for Daisi SDK.
"""

from typing import Optional

import grpc

from protos.v1 import Hosts_pb2, Hosts_pb2_grpc
from protos.v1.models import HostModels_pb2

from ..base_client import BaseClient
from ..config import DaisiConfig
from ..exceptions import DaisiError


class HostClient(BaseClient):
    """Client for host management operations."""

    def __init__(self, config: Optional[DaisiConfig] = None) -> None:
        """Initialize host client.

        Args:
            config: Daisi configuration.
        """
        super().__init__(config)
        self._stub: Optional[Hosts_pb2_grpc.HostsProtoStub] = None

    @property
    def stub(self) -> Hosts_pb2_grpc.HostsProtoStub:
        """Get or create the gRPC stub."""
        if self._stub is None:
            self._stub = Hosts_pb2_grpc.HostsProtoStub(self._get_channel())
        return self._stub

    def get_hosts(self) -> list[HostModels_pb2.Host]:
        """Get list of available hosts.

        Returns:
            List of Host objects.

        Raises:
            DaisiError: If request fails.
        """
        request = HostModels_pb2.GetHostsRequest()

        try:
            response = self.stub.GetHosts(request, metadata=self._get_metadata())
            return list(response.Hosts)
        except grpc.RpcError as e:
            raise DaisiError(f"Failed to get hosts: {e.details()}") from e

    def update_host(self, host: HostModels_pb2.Host) -> tuple[bool, str]:
        """Update host information.

        Args:
            host: Host object with updated information.

        Returns:
            Tuple of (success, message).

        Raises:
            DaisiError: If update fails.
        """
        request = HostModels_pb2.UpdateHostRequest(Host=host)

        try:
            response = self.stub.UpdateHost(request, metadata=self._get_metadata())
            return response.Success, response.Message
        except grpc.RpcError as e:
            raise DaisiError(f"Failed to update host: {e.details()}") from e

    def register_host(self, host: HostModels_pb2.Host) -> tuple[str, str]:
        """Register a new host.

        Args:
            host: Host object to register.

        Returns:
            Tuple of (secret_key, host_id).

        Raises:
            DaisiError: If registration fails.
        """
        request = HostModels_pb2.RegisterHostRequest(Host=host)

        try:
            response = self.stub.RegisterHost(request, metadata=self._get_metadata())
            return response.SecretKey, response.HostId
        except grpc.RpcError as e:
            raise DaisiError(f"Failed to register host: {e.details()}") from e

    def get_secret_key(self, host_id: str) -> str:
        """Get the secret key for a host.

        Args:
            host_id: ID of the host.

        Returns:
            Secret key for the host.

        Raises:
            DaisiError: If request fails.
        """
        request = HostModels_pb2.GetSecretKeyRequest(HostId=host_id)

        try:
            response = self.stub.GetSecretKey(request, metadata=self._get_metadata())
            return response.SecretKey
        except grpc.RpcError as e:
            raise DaisiError(f"Failed to get host secret key: {e.details()}") from e

    def archive(self, host_id: str) -> bool:
        """Archive a host and remove it from service.

        Args:
            host_id: ID of the host to archive.

        Returns:
            True if archive was successful.

        Raises:
            DaisiError: If archive fails.
        """
        request = HostModels_pb2.ArchiveHostRequest(HostId=host_id)

        try:
            response = self.stub.Archive(request, metadata=self._get_metadata())
            return response.Success
        except grpc.RpcError as e:
            raise DaisiError(f"Failed to archive host: {e.details()}") from e
