from typing import Generic, Optional, TypeVar, override
from flut._flut.engine import FlutObject, FlutRealtimeObject, generate_flut_id, get_engine


class BuildContext(FlutRealtimeObject):

    def __init__(self, oid: int):
        super().__init__("BuildContext", oid=oid)

    @override
    def _flut_pack(self) -> dict:
        return self._flut_base_props()


class Widget(FlutObject):

    def __init__(self, flut_type: str, key=None):
        super().__init__(flut_type)
        self._flut_id = generate_flut_id()
        self._key = key

    @override
    def _flut_base_props(self) -> dict:
        result = super()._flut_base_props()
        result["_flut_id"] = self._flut_id
        result["key"] = self._key
        return result


class StatelessWidget(Widget):

    def __init__(self, key=None):
        super().__init__("StatelessWidget", key=key)

    def build(self, context):
        raise NotImplementedError

    @override
    def _flut_pack(self) -> dict:
        get_engine().widget_registry[self._flut_id] = self
        result = self._flut_base_props()
        result["className"] = self.__class__.__name__
        return result


TWidget = TypeVar("TWidget", bound="StatefulWidget")


class State(Generic[TWidget]):

    def __init__(self):
        self._flut_widget: Optional[TWidget] = None
        self._flut_id: Optional[str] = None
        self._flut_last_build_context: Optional[BuildContext] = None
        self._flut_registered_actions: list = []
        self._flut_action_counter: int = 0

    def _allocate_action_id(self) -> str:
        action_id = f"{self._flut_id}:a{self._flut_action_counter}"
        self._flut_action_counter += 1
        self._flut_registered_actions.append(action_id)
        return action_id

    @property
    def widget(self) -> TWidget:
        return self._flut_widget

    @property
    def context(self) -> Optional[BuildContext]:
        return self._flut_last_build_context

    def initState(self):
        pass

    def didUpdateWidget(self, oldWidget: TWidget):
        pass

    def dispose(self):
        pass

    def build(self, context: BuildContext):
        raise NotImplementedError

    def setState(self, fn):
        if fn:
            fn()

        engine = get_engine()
        if engine is None:
            raise RuntimeError("Engine is not initialized.")
        engine.notify_set_state(self._flut_id)


class StatefulWidget(Widget):

    def __init__(self, key=None):
        super().__init__("StatefulWidget", key=key)

    def createState(self):
        raise NotImplementedError

    @override
    def _flut_pack(self) -> dict:
        get_engine().widget_registry[self._flut_id] = self
        result = self._flut_base_props()
        result["className"] = self.__class__.__name__
        return result
