"""
Networks client for Daisi SDK.
"""

from typing import Optional

import grpc

from protos.v1 import Networks_pb2, Networks_pb2_grpc
from protos.v1.models import NetworkModels_pb2, SystemModels_pb2

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


class NetworkClient(BaseClient):
    """Client for network management operations."""

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

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

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

    def get(
        self,
        network_id: Optional[str] = None,
        is_public: bool = False,
        page_index: Optional[int] = None,
        page_size: Optional[int] = None,
    ) -> tuple[list[NetworkModels_pb2.Network], int]:
        """Get networks.

        Args:
            network_id: Filter by specific network ID.
            is_public: Filter by public networks.
            page_index: Page index for pagination.
            page_size: Number of items per page.

        Returns:
            Tuple of (networks list, total count).

        Raises:
            DaisiError: If request fails.
        """
        paging = SystemModels_pb2.PagingInfo()
        if page_index is not None:
            paging.PageIndex = page_index
        if page_size is not None:
            paging.PageSize = page_size

        request = NetworkModels_pb2.GetNetworksRequest(
            Paging=paging,
            IsPublic=is_public,
        )
        if network_id:
            request.NetworkId = network_id

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

    def create(
        self, network: NetworkModels_pb2.Network
    ) -> tuple[Optional[NetworkModels_pb2.Network], Optional[str]]:
        """Create a new network.

        Args:
            network: Network object to create.

        Returns:
            Tuple of (created network, response message).

        Raises:
            DaisiError: If creation fails.
        """
        request = NetworkModels_pb2.CreateNetworkRequest(Network=network)

        try:
            response = self.stub.Create(request, metadata=self._get_metadata())
            return (
                response.Network if response.HasField("Network") else None,
                response.Response if response.Response else None,
            )
        except grpc.RpcError as e:
            raise DaisiError(f"Failed to create network: {e.details()}") from e

    def update(self, network: NetworkModels_pb2.Network) -> tuple[bool, Optional[str]]:
        """Update a network.

        Args:
            network: Network object with updated information.

        Returns:
            Tuple of (success, message).

        Raises:
            DaisiError: If update fails.
        """
        request = NetworkModels_pb2.UpdateNetworkRequest(Network=network)

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

    def archive(self, network_id: str) -> tuple[bool, Optional[str]]:
        """Archive a network.

        Args:
            network_id: ID of the network to archive.

        Returns:
            Tuple of (success, message).

        Raises:
            DaisiError: If archive fails.
        """
        request = NetworkModels_pb2.ArchiveNetworkRequest(NetworkId=network_id)

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