import asyncio
from asyncio.locks import Event

from parat.services import (
    ParaT,
    PipelineBuilder,
    PropertyManager,
    ReactiveCommandHelper,
)
from paraview.modules.vtkRemotingPythonAsyncCore import vtkPythonObservableWrapperUtilities
import vtk
import sys

from vtk.vtkCommonCore import vtkCommand

EventCounter = 0
cond = asyncio.Condition()

async def monitorViewOutput(view):

    global cond
    async for _ in vtkPythonObservableWrapperUtilities.GetIterator(
        view.GetViewOutputObservable()
    ):
        async with cond:
            cond.notify_all()

async def Observe(observable):
    global EventCounter
    async for event in observable:
        print(event)
        EventCounter += 1


async def main():
    App = ParaT()
    session = await App.initialize()

    builder = PipelineBuilder(session)

    sphere = await builder.CreateProxy(
        "sources", "SphereSource", ThetaResolution=80, Radius=2
    )
    shrink = await builder.CreateProxy(
        "filters", "ShrinkFilter", Input=sphere, ShrinkFactor=0.3
    )

    observer = ReactiveCommandHelper(sphere, vtkCommand.PropertyModifiedEvent)
    task = asyncio.create_task(Observe(observer.GetObservable()))

    await asyncio.sleep(0.1)

    pmanager = PropertyManager()
    pmanager.SetValues(sphere, Radius=3, Center=[1, 2, 3], EndPhi=90)

    await asyncio.sleep(0.1)

    view = await builder.CreateProxy("views", "RenderView")
    pmanager.SetValues(view, StreamOutput=True)
    viewResultTask = asyncio.create_task(monitorViewOutput(view))

    values = pmanager.GetValues(view)

    # before we 'update' the view, let's install an interactor on the view
    # so that the viewport dimensions, cameras of the client and server's render windows sync up.
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(view.GetRenderWindow())

    # make sure ProxyProperties with nullptr as default value are transformed to None
    assert values["BackgroundTexture"] is None

    representation = await builder.CreateRepresentation(
        shrink, 0, view, "GeometryRepresentation"
    )

    await pmanager.Update(view)
    view.ResetCameraUsingVisiblePropBounds()

    if "-I" in sys.argv:
        while not iren.GetDone():
            iren.ProcessEvents()
            await asyncio.sleep(0.01)
            if iren.GetKeyCode() == "s":
                pmanager.SetVisibility(representation, view, True)
            if iren.GetKeyCode() == "h":
                pmanager.SetVisibility(representation, view, False)
    else:
        for i in range(5):
            view.GetCamera().Azimuth(10)
            view.StillRender()
            async with cond:
                await cond.wait()

    view.UnsubscribeOutputStreams()
    await viewResultTask

    status = await builder.DeleteProxy(shrink)
    assert status == True

    observer.Unsubscribe()
    await task
    assert EventCounter != 0

    await App.finalize()


asyncio.run(main())
