"""
Generated by pbreflect (https://github.com/ValeriyMenshikov/pbreflect).

Generated client code for {{ package }} using pbreflect.

This module contains auto-generated gRPC client classes for the {{ package }} package.
It provides strongly-typed {% if async_mode %}async{% else %}sync{% endif %} gRPC clients that follow the "duck typing" principle.
"""

import grpc
{% if async_mode %}
import grpc.aio
{% endif %}
from typing import Dict, List, Optional, Union, Any, Callable, ClassVar, Type, cast, Iterator, Tuple, Iterable
from google.protobuf.message import Message
from abc import ABC

{# Import all required modules, skipping duplicates #}
{% for import_line in imports %}
{% if import_line.startswith("import grpc") or import_line.startswith("from typing") or import_line.startswith("from google.protobuf.message") or import_line.startswith("from nuke.grpc_client") or import_line.startswith("from abc") %}
{% else %}
{{ import_line }}
{% endif %}
{% endfor %}

{% if services %}
{% for service in services %}
class _{{ service.name }}Stub:
    """Internal stub class for {{ service.name }} service.

    This class provides direct access to the gRPC methods exposed by the service.
    It should not be used directly, but through the {{ service.name }}Client class.
    """

    def __init__(self, channel: {% if async_mode %}grpc.aio.Channel{% else %}grpc.Channel{% endif %}) -> None:
        """Initialize the stub with a gRPC channel.

        Args:
            channel: gRPC channel for communication
        """
        {# Generate method stubs based on streaming type #}
        {% for method in service.methods %}
        {% if method.is_client_streaming and method.is_server_streaming %}
        self.{{ method.original_name }} = channel.stream_stream(
            "/{% if package %}{{ package }}.{% endif %}{{ service.name }}/{{ method.original_name }}",
            request_serializer={{ method.input_type }}.SerializeToString,
            response_deserializer={{ method.output_type }}.FromString,
        )
        {% elif method.is_client_streaming %}
        self.{{ method.original_name }} = channel.stream_unary(
            "/{% if package %}{{ package }}.{% endif %}{{ service.name }}/{{ method.original_name }}",
            request_serializer={{ method.input_type }}.SerializeToString,
            response_deserializer={{ method.output_type }}.FromString,
        )
        {% elif method.is_server_streaming %}
        self.{{ method.original_name }} = channel.unary_stream(
            "/{% if package %}{{ package }}.{% endif %}{{ service.name }}/{{ method.original_name }}",
            request_serializer={{ method.input_type }}.SerializeToString,
            response_deserializer={{ method.output_type }}.FromString,
        )
        {% else %}
        self.{{ method.original_name }} = channel.unary_unary(
            "/{% if package %}{{ package }}.{% endif %}{{ service.name }}/{{ method.original_name }}",
            request_serializer={{ method.input_type }}.SerializeToString,
            response_deserializer={{ method.output_type }}.FromString,
        )
        {% endif %}
        {% endfor %}


class {{ service.name }}Client:
    """Client for the {{ service.name }} service.

    This class provides a strongly-typed {% if async_mode %}async{% else %}sync{% endif %} interface to the gRPC service.
    """

    def __init__(self, channel: {% if async_mode %}grpc.aio.Channel{% else %}grpc.Channel{% endif %}) -> None:
        """Initialize the client with a gRPC channel.

        Args:
            channel: gRPC channel for communication
        """
        self._stub = _{{ service.name }}Stub(channel)

    {% for method in service.methods %}
    {% if async_mode %}    async {% endif %}    def {{ method.name }}(
        self,
        {% if method.is_client_streaming %}
        request_iterator: Iterator[{{ method.input_type }}],
        {% else %}
        request: {{ method.input_type }},
        {% endif %}
        metadata: {% if async_mode %}Optional[grpc.aio.Metadata]{% else %}Optional[List[Tuple[str, str]]]{% endif %} = None,
        timeout: Optional[float] = None,
    ){% if async_mode %}{% if method.is_client_streaming and method.is_server_streaming %} -> grpc.aio.StreamStreamCall[{{ method.input_type }}, {{ method.output_type }}]{% elif method.is_client_streaming %} -> grpc.aio.StreamUnaryCall[{{ method.input_type }}, {{ method.output_type }}]{% elif method.is_server_streaming %} -> grpc.aio.UnaryStreamCall[{{ method.input_type }}, {{ method.output_type }}]{% else %} -> {{ method.output_type }}{% endif %}{% else %}{% if method.is_server_streaming %} -> Iterable[{{ method.output_type }}]{% else %} -> {{ method.output_type }}{% endif %}{% endif %}:
        call = self._stub.{{ method.original_name }}(
            {% if method.is_client_streaming %}
            request_iterator,
            {% else %}
            request,
            {% endif %}
            metadata=metadata,
            timeout=timeout,
        )
        {% if async_mode %}
        {% if method.is_client_streaming and method.is_server_streaming %}
        return cast(grpc.aio.StreamStreamCall[{{ method.input_type }}, {{ method.output_type }}], call)
        {% elif method.is_client_streaming %}
        return cast(grpc.aio.StreamUnaryCall[{{ method.input_type }}, {{ method.output_type }}], call)
        {% elif method.is_server_streaming %}
        return cast(grpc.aio.UnaryStreamCall[{{ method.input_type }}, {{ method.output_type }}], call)
        {% else %}
        return await cast(grpc.aio.UnaryUnaryCall[{{ method.input_type }}, {{ method.output_type }}], call)
        {% endif %}
        {% else %}
        return call
        {% endif %}
    {% endfor %}
{% endfor %}
{% endif %}
