"""RadiensCore RPC wrappers — thin service layer (proto only)."""

from __future__ import annotations

from typing import TYPE_CHECKING

import grpc

from radiens_core._converters._dataset import file_type_to_proto, guess_file_type
from radiens_core._generated import (
    common_pb2,
    datasource_pb2,
    radiensserver_pb2_grpc,
)
from radiens_core._transport._errors import handle_grpc_error
from radiens_core.models.common import ClientType
from radiens_core.models.dataset import RadiensFileType

if TYPE_CHECKING:
    from collections.abc import Iterable

    from radiens_core._transport._channel_pool import ChannelPool
    from radiens_core.models.dataset import DatasetMetadata


def get_hd_snapshot_py_proto(
    pool: ChannelPool,
    addr: str,
    request: common_pb2.HDSnapshotRequest2,
) -> common_pb2.HDSnapshot2:
    """Send ``GetHDSnapshotPy`` RPC, return raw proto response."""
    channel = pool.get_channel(addr)
    stub = radiensserver_pb2_grpc.RadiensCoreStub(channel)
    try:
        return stub.GetHDSnapshotPy(request)
    except grpc.RpcError as ex:
        handle_grpc_error(ex, ClientType.VIDERE)
        raise  # unreachable, but satisfies mypy


def set_datasource(
    pool: ChannelPool,
    addr: str,
    path: str,
) -> DatasetMetadata:
    """Link a data file via SetDataSourceFromFile RPC.

    Returns domain DatasetMetadata.
    """
    import os

    from radiens_core._converters._dataset import dataset_metadata_from_proto

    ft = guess_file_type(path)
    base_name = os.path.splitext(os.path.basename(path))[0]

    # Normalize XDAT base name by stripping standard suffixes if present
    if ft == RadiensFileType.XDAT:
        if base_name.endswith("_data"):
            base_name = base_name[:-5]
        elif base_name.endswith("_timestamp"):
            base_name = base_name[:-10]

    dir_path = os.path.dirname(path) or "."

    req = datasource_pb2.DataSourceSetSaveRequest(
        path=dir_path,
        baseName=base_name,
        fileType=file_type_to_proto(ft),
    )

    channel = pool.get_channel(addr)
    stub = radiensserver_pb2_grpc.RadiensCoreStub(channel)
    try:
        res = stub.SetDataSourceFromFile(req)
    except grpc.RpcError as ex:
        handle_grpc_error(ex, ClientType.VIDERE)
        raise  # unreachable, but satisfies mypy

    return dataset_metadata_from_proto(res)


def set_protocol_proto(
    pool: ChannelPool,
    addr: str,
    request: common_pb2.Protocol,
) -> common_pb2.Protocol:
    """Send ``SetProtocol`` RPC, return raw proto response."""
    channel = pool.get_channel(addr)
    stub = radiensserver_pb2_grpc.RadiensCoreStub(channel)
    try:
        return stub.SetProtocol(request)
    except grpc.RpcError as ex:
        handle_grpc_error(ex, ClientType.CURATE)
        raise  # unreachable, but satisfies mypy


def apply_protocol_proto(
    pool: ChannelPool,
    addr: str,
    request: common_pb2.ProtocolRequest,
) -> Iterable[common_pb2.ApplyProtocolProgress]:
    """Send ``ApplyProtocol`` RPC, return stream of ApplyProtocolProgress."""
    channel = pool.get_channel(addr)
    stub = radiensserver_pb2_grpc.RadiensCoreStub(channel)
    try:
        return stub.ApplyProtocol(request)
    except grpc.RpcError as ex:
        handle_grpc_error(ex, ClientType.CURATE)
        raise  # unreachable, but satisfies mypy
