import time
from typing import Callable, Optional

from google.protobuf.timestamp_pb2 import Timestamp

from clients._path_setup import ensure_paths

ensure_paths()

from clients.base_client import RobotClientBase
from cmvr.api import camera_command_pb2 as pb
from cmvr.api import camera_service_pb2_grpc as rpc
from cmvr.api import common_pb2


class CameraClient(RobotClientBase):
    """Client for CameraService RGB image RPCs."""

    def _init_stubs(self, channel):
        self.stub = rpc.CameraServiceStub(channel)

    @staticmethod
    def _make_header(device_id: str):
        header = common_pb2.CommandHeader.Request()
        header.device_id = device_id
        timestamp = Timestamp()
        timestamp.GetCurrentTime()
        header.timestamp.CopyFrom(timestamp)
        return header

    def start_camera(self, device_id: str):
        request = pb.StartCameraCommand.Request(header=self._make_header(device_id))
        return self.stub.StartCamera(request, timeout=self.timeout)

    def stop_camera(self, device_id: str):
        request = pb.StopCameraCommand.Request(header=self._make_header(device_id))
        return self.stub.StopCamera(request, timeout=self.timeout)

    def get_rgb_image(self, device_id: str):
        request = pb.GetRGBImageCommand.Request(header=self._make_header(device_id))
        return self.stub.GetRGBImage(request, timeout=self.timeout)

    def get_rgb_image_stream(
        self,
        device_id: str,
        stop_requested: Optional[Callable[[], bool]] = None,
        request_interval: float = 0.001,
    ):
        should_stop = stop_requested or (lambda: False)

        def request_gen():
            while not should_stop():
                yield pb.GetRGBImageStreamCommand.Request(
                    header=self._make_header(device_id),
                    eof=False,
                )
                time.sleep(request_interval)

            yield pb.GetRGBImageStreamCommand.Request(
                header=self._make_header(device_id),
                eof=True,
            )

        return self.stub.GetRGBImageStream(request_gen())


GetRGBImageStreamClient = CameraClient
