import asyncio

from parat.pythonApplication import *
from parat.pipelineBuilder import *
from parat.activeObjects import *

from paraview.modules.vtkRemotingServerManager import (
    vtkSMProxySelectionModel,
)  # for vtkSMProxySelectionModel.SELECT


async def observeActive(activeObjects):
    observed = []
    async for value in activeObjects.GetCurrentObservable():
        if value:
            observed.append(value.GetXMLName())
        else:
            observed.append(None)

    return observed


async def observeSelection(activeObjects):
    observed = []
    async for value in activeObjects.GetSelectionObservable():
        value = [v.GetXMLName() if v is not None else None for v in value]
        observed.append(value)
    return observed


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

    activeObjects = ActiveObjects(session, "ActiveSources")

    task1 = asyncio.create_task(observeActive(activeObjects))
    task2 = asyncio.create_task(observeSelection(activeObjects))

    builder = PipelineBuilder(session)

    # proxy creation updates active and selection
    sphere = await builder.CreateSource(
        "sources", "SphereSource", ThetaResolution=80, Radius=2
    )
    shrink = await builder.CreateFilter(
        "filters", "ShrinkFilter", Input=sphere, ShrinkFactor=0.3
    )
    # add manually proxy to the selection
    activeObjects.Select(sphere, vtkSMProxySelectionModel.SELECT)

    # set manually active proxy
    activeObjects.SetCurrentProxy(sphere, vtkSMProxySelectionModel.CLEAR)

    # clear selection
    activeObjects.Select(None, vtkSMProxySelectionModel.CLEAR)
    # select two elements
    activeObjects.Select([sphere, shrink], vtkSMProxySelectionModel.SELECT)

    status = await builder.DeleteProxy(shrink)
    status = await builder.DeleteProxy(sphere)

    # destroying the activeObjectsObserver terminates the async iterator
    activeObjects.UnsubscribeAll()

    await task1
    await task2
    observedActive = task1.result()
    observedSelection = task2.result()

    assert observedActive == [
        None,
        "SphereSource",
        "ShrinkFilter",
        "SphereSource",
        None,
    ]
    assert observedSelection == [
        [],
        ["SphereSource"],
        ["ShrinkFilter"],
        ["ShrinkFilter", "SphereSource"],
        [],
        ["SphereSource", "ShrinkFilter"],
        [],
    ]

    #  activeObjects can NOT be reused:
    exceptionRaised = False
    try:
        task1 = asyncio.create_task(observeActive(activeObjects))

        sphere = await builder.CreateSource(
            "sources", "SphereSource", ThetaResolution=80, Radius=2
        )
        activeObjects.UnsubscribeAll()

        await task1
    except Exception as exc:
        exceptionRaised = True
        # print(exc)

    assert exceptionRaised, "Reusing unsubscribed microservice did not raise an error"

    await App.finalize()


asyncio.run(main())
