import paraview.modules.vtkRemotingMicroservices
from paraview.modules.vtkRemotingServerManager import vtkClientSession, vtkSMProxy
from paraview.modules.vtkRemotingPythonAsyncCore import (
    vtkPythonObservableWrapperUtilities,
)

from parat.services.properties import PropertyManager


class PipelineBuilder(paraview.modules.vtkRemotingMicroservices.vtkPTSPipelineBuilder):
    """
    A thin Python Wrapper around vtkPTSPipelineBuilder.
    """

    def __init__(self, session):

        if not isinstance(session, vtkClientSession):
            raise TypeError(" 'session' argument is not of type vtkClientSession")

        super().SetSession(session)

    async def CreateProxy(self, group, name, **kwargs):
        """Given a group and proxy name, create and return a proxy instance.
        The proxy is initialized and registered with the session proxy manager.
        kwargs can be any property of the proxy.
        - If the proxy is a filter passing the `Input` is required.

        Example:

          sphere = await builder.CreateProxy("sources","SphereSource",Radius=10,Center=[0,0,7])
          filter = await builder.CreateProxy("filters","ShrinkFilter",Input=sphere, ShrinkFactor=0.3)

        """

        proxy = None
        if group == "sources":
            proxy = await vtkPythonObservableWrapperUtilities.GetFuture(
                super().CreateSource(group, name)
            )
        elif group == "filters":
            Input = kwargs.get("Input", None)
            if Input is None:
                raise RuntimeError(f"No Input provided for {name}")
            del kwargs["Input"]

            proxy = await vtkPythonObservableWrapperUtilities.GetFuture(
                super().CreateFilter(group, name, Input)
            )
        elif group == "views":
            proxy = await vtkPythonObservableWrapperUtilities.GetFuture(
                super().CreateView(group, name)
            )
        else:
            raise RuntimeError(f"Insupported group name {group}")

        if kwargs:
            pm = PropertyManager()
            pm.SetValues(proxy, **kwargs)

        return proxy

    async def CreateRepresentation(
        self, producer, outputPort, view, representationType, **kwargs
    ):
        representation = await vtkPythonObservableWrapperUtilities.GetFuture(
            super().CreateRepresentation(producer, outputPort, view, representationType)
        )

        if kwargs:
            pm = PropertyManager()
            pm.SetValues(representation, **kwargs)

        return representation

    async def DeleteProxy(self, proxy):
        if not isinstance(proxy, vtkSMProxy):
            inputType = type(proxy)
            raise TypeError(
                f" `proxy` argument (type: {inputType}  should be of type vtkSMProxy"
            )
        try:
            status = await vtkPythonObservableWrapperUtilities.GetFuture(
                super().DeleteProxy(proxy)
            )
        except RuntimeError:
            import traceback

            traceback.print_exc()
            raise RuntimeError("error")

        return status


class PipelineViewer(paraview.modules.vtkRemotingMicroservices.vtkPTSPipelineViewer):
    """
    A thin Python Wrapper around vtkPTSPipelineViewer.
    """

    def __init__(self, session):

        if not isinstance(session, vtkClientSession):
            raise TypeError(" 'session' argument is not of type vtkClientSession")

        super().SetSession(session)

    def GetObservable(self):
        return vtkPythonObservableWrapperUtilities.GetIterator(super().GetObservable())
