# export PYTHONPATH=/home/seb/Documents/code/Async/build/lib/python3.10/site-packages
# export LD_LIBRARY_PATH=/home/seb/Documents/code/Async/build/lib
#
# python3.10 -m venv pv-venv
# source ./pv-venv/bin/activate
# pip install -U pip
# pip install trame
#
# python ./paraview/Remoting/Microservices/Testing/Trame/TestStreaming.py

# -----------------------------------------------------------------------------
# Async imports
# -----------------------------------------------------------------------------

import asyncio

from parat.services import ParaT, PipelineBuilder, DefinitionManager

# -----------------------------------------------------------------------------
# Trame imports
# -----------------------------------------------------------------------------

from trame.app import get_server, asynchronous
from trame.ui.vuetify import SinglePageLayout
from trame.widgets import vuetify, html

# -----------------------------------------------------------------------------
# Trame setup
# -----------------------------------------------------------------------------


class App:
    def __init__(self, server=None):
        if server is None:
            server = get_server()

        self.state = server.state
        self.ctrl = server.controller
        self._app = ParaT()
        self._ready = False

    async def initialize(self):
        self._session = await self._app.initialize()
        self._builder = PipelineBuilder(self._session)
        self._def_mgt = DefinitionManager(self._session)
        self._ready = True

    async def finallize(self):
        await self._app.finalize()


async def start():
    global GLOBAL

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

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

    view = await builder.CreateView("views", "RenderView")
    # Tells the view to use video codecs for higher compression ratio and lower latency.
    view.UseCompressedStreamsOn()
    # By turning on both, we can see the decompressed frame in the render window
    # and get a stream of webm chunks from the view.GetWEBMChunkObservable()
    view.DecodeStreamToRenderWindowAndWriteWebmChunks()
    chunkTask = asyncio.create_task(handle_stream(view))

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

    pmanager.SetValues(view, ViewSize=[300, 300])
    await asyncio.sleep(0.1)

    await pmanager.Update(view)
    view.ResetCameraUsingVisiblePropBounds()
    await asyncio.sleep(0.1)

    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(view.GetRenderWindow())
    iren.EnableRenderOff()
    # iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera()
    iren.Initialize()

    camera = view.GetCamera()

    GLOBAL["app"] = app
    GLOBAL["session"] = session
    GLOBAL["session"] = session
    GLOBAL["builder"] = builder
    GLOBAL["pmanager"] = pmanager
    GLOBAL["representation"] = representation
    GLOBAL["view"] = view
    GLOBAL["iren"] = iren
    GLOBAL["down"] = False
    GLOBAL["camera"] = camera
    GLOBAL["animating"] = False

    with state:
        state.view_ready = True

    print("Start done")
    await chunkTask
    print("Exit done")
    await app.finalize()


@ctrl.add("on_server_ready")
def on_ready(**kwargs):
    asynchronous.create_task(start())


@ctrl.set("on_mouse")
def on_event(event, x, y):
    # 'type': 'mousemove', 'altKey': False, 'shiftKey': False

    # https://github.com/Kitware/VTK/blob/master/Web/Core/vtkWebApplication.cxx#L260-L353
    if "iren" not in GLOBAL:
        return
    mt_0 = GLOBAL["camera"].GetMTime()
    print("on_mouse", event, x, y)

    iren = GLOBAL["iren"]

    iren.SetEventInformation(
        x,
        y,
        0,  # event["controlKey"],
        event["shiftKey"],
        " ",  # event->GetKeyCode(),
        0,  # event->GetRepeatCount(),
    )
    iren.MouseMoveEvent()

    if GLOBAL["down"] != event["shiftKey"]:
        if event["shiftKey"]:
            print("down")
            iren.LeftButtonPressEvent()
            GLOBAL["down"] = True
            enable_animation(True)
        else:
            print("up")
            iren.LeftButtonReleaseEvent()
            GLOBAL["down"] = False
            enable_animation(False)

    # m_type = event["type"]

    # iren.ProcessEvents() # make things super slow...

    # Should be done in animation loop
    # GLOBAL["view"].StillRender()


async def spin():
    t_0 = time.time()
    delta = 1
    while state.spinning:
        GLOBAL["view"].GetCamera().Azimuth(1)
        GLOBAL["view"].StillRender()
        await asyncio.sleep(1 / state.speed)
        t_1 = time.time()
        with state:
            state.dt_spin = t_1 - t_0
        t_0 = t_1
        state.progress += delta
        if state.progress > 99:
            delta = -1
        if state.progress < 1:
            delta = 1


@state.change("spinning")
def on_spin_change(spinning, **kwargs):
    if spinning:
        asynchronous.create_task(spin())


@state.change("size")
def on_size(size, **kwargs):
    if "view" in GLOBAL:
        GLOBAL["pmanager"].SetValues(GLOBAL["view"], ViewSize=[int(size), int(size)])


# -----------------------------------------------------------------------------
# Web App setup
# -----------------------------------------------------------------------------

state.trame__title = "VTK Rendering"
state.update(
    dict(
        view_ready=False,
        dt=1,
        dt_spin=1,
    )
)

with SinglePageLayout(server) as layout:
    layout.title.set_text("")
    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VSelect(
            v_model=("size", 250),
            dense=True,
            hide_details=True,
            items=("[250, 500, 1000, 2000, 3000, 4000]",),
            style="max-width: 150px;",
        )
        html.Div(
            "{{ Math.round(1/dt) }} spin/ {{ Math.round(1/dt) }} render/ {{ speed }} fps",
            style="width: 300px; text-align: center;",
        )
        vuetify.VSlider(
            v_model=("speed", 20),
            dense=True,
            hide_details=True,
            min=1,
            max=100,
            step=1,
            style="max-width: 200px;",
        )
        vuetify.VIcon(
            "mdi-check-bold", v_show="view_ready", color="green", classes="mx-2"
        )
        vuetify.VCheckbox(
            v_model=("spinning", False),
            dense=True,
            hide_details=True,
            on_icon="mdi-pause-octagon-outline",
            off_icon="mdi-axis-z-rotate-counterclockwise",
        )
        vuetify.VProgressLinear(
            v_model=("progress", 0),
            hide_details=True,
            dense=True,
            absolute=True,
            bottom=True,
        )

    with layout.content:
        with vuetify.VContainer(
            fluid=True,
            classes="pa-0 fill-height",
            mousedown=(
                ctrl.on_mouse,
                "[utils.vtk.event($event), event.clientX, event.clientY]",
            ),
            mouseup=(
                ctrl.on_mouse,
                "[utils.vtk.event($event), event.clientX, event.clientY]",
            ),
            mousemove=(
                ctrl.on_mouse,
                "[utils.vtk.event($event), event.clientX, event.clientY]",
            ),
            __events=["mousedown", "mouseup", "mousemove", "mouseenter", "mouseleave"],
        ):
            video_stream.TrameVideoStream(
                encoding=("encoding", ""),
                style="border: 1px solid #333; max-width: 100%;",
                classes="mx-auto",
            )


if __name__ == "__main__":
    server.start()
