import time
import asyncio
from paraview.modules.vtkRemotingPythonAsyncCore import (
    vtkPythonObservableWrapperUtilities,
)
from vtkmodules.vtkRenderingCore import vtkRenderWindowInteractor
from parat.services import PropertyManager
from trame.app import asynchronous


class ViewAdapter:
    def __init__(self, view, name, target_fps=30):
        self._proxy_handler = PropertyManager()
        self._view = view
        self.area_name = name
        self.streamer = None
        self.last_meta = None
        self.animating = False
        self.target_fps = target_fps

        self.last_button = -1
        self.last_view_height = 300
        self._iren = vtkRenderWindowInteractor()
        self._iren.SetRenderWindow(view.GetRenderWindow())
        self._iren.EnableRenderOff()

        asynchronous.create_task(self._listen_to_view())

    async def _listen_to_view(self):
        async for package in vtkPythonObservableWrapperUtilities.GetIterator(
            self._view.GetViewOutputObservable()
        ):
            if package:
                # print(package.GetMimeType(), " ----- ", package.GetCodecLongName())
                self.push(
                    memoryview(package.GetData()),
                    dict(
                        type=package.GetMimeType(),
                        codec=package.GetCodecLongName(),
                        w=package.GetDisplayWidth(),
                        h=package.GetDisplayHeight(),
                        st=int(time.time_ns() / 1000000),
                        key=("key" if package.GetIsKeyFrame() else "delta"),
                    ),
                )

    async def _animate(self):
        while self.animating:
            self._view.InteractiveRender()
            await asyncio.sleep(1 / self.target_fps)
        self._view.StillRender()

    def set_streamer(self, stream_manager):
        self.streamer = stream_manager

    def update_size(self, origin, size):
        need_video_header = size.get("videoHeader", 0)
        width = int(size.get("w", 300))
        height = int(size.get("h", 300))

        self.last_view_height = height
        self._proxy_handler.SetValues(
            self._view,
            ViewSize=(width, height),
            RequestMediaInitializationSegment=need_video_header,
            force_push=True,
        )
        self._view.StillRender()

    def push(self, content, meta=None):
        if meta is not None:
            self.last_meta = meta
        self.streamer.push_content(self.area_name, self.last_meta, content)

    def on_interaction(self, origin, event):
        event_type = event.get("t", "mouse-down")
        position = event.get("p", (0, 0))
        button = event.get("b", 0)
        modifier_shift = event.get("shift", 0)
        modifier_ctrl = event.get("ctrl", 0)
        # modifier_alt = event.get("alt", 0)
        # modifier_cmd = event.get("cmd", 0)
        # modifier_fn = event.get("fn", 0)
        button_changed = self.last_button != button
        x = int(position[0])
        y = int(self.last_view_height - position[1])
        self._iren.SetEventInformation(
            x,
            y,
            modifier_ctrl,
            modifier_shift,
            "",  # key code
            0,  # repeat count
        )
        self._iren.MouseMoveEvent()

        if event_type == "mouse-down" and not self.animating:
            self.animating = True
            asynchronous.create_task(self._animate())
            if button == 0:
                self._iren.LeftButtonPressEvent()
            if button == 1:
                self._iren.MiddleButtonPressEvent()
            if button == 2:
                self._iren.RightButtonPressEvent()

        if event_type == "mouse-up":
            self.animating = False
            if button == 0:
                self._iren.LeftButtonReleaseEvent()
            if button == 1:
                self._iren.MiddleButtonReleaseEvent()
            if button == 2:
                self._iren.RightButtonReleaseEvent()
