from typing import Any, Mapping, Optional
from instaui.internal.ui._expr.literal_expr import UILiteralExpr
from instaui.internal.ui.app_context import get_current_scope
from instaui.internal.ui.app_index import new_scope_if_needed
from instaui.internal.ui.bindable import BindableMixin, VarableBindHelper
from instaui.internal.ui.enums import InputBindingType
from instaui.internal.ui.path_var import PathVar
from instaui.internal.ui.protocol import ObservableProtocol
from instaui.internal.ui.variable import Variable


class ExprComputed(Variable, PathVar, BindableMixin, ObservableProtocol):
    def __init__(
        self,
        fn_code: str,
        bindings: Optional[Mapping[str, Any]] = None,
    ) -> None:
        new_scope_if_needed()
        define_scope = get_current_scope()
        self.code = fn_code
        self._bindings = UILiteralExpr.try_parse_dict(bindings) if bindings else None

        self._bind_helper = VarableBindHelper(
            self,
            define_scope.register_expr_computed,
            define_scope=define_scope,
            lazy_mark_used=[self._bindings],
        )

    @property
    def _used(self) -> bool:
        return self._bind_helper.used

    def _mark_used(self) -> None:
        self._bind_helper.mark_used()

    def _mark_provided(self) -> None:
        self._bind_helper.mark_provided()

    @property
    def _define_scope_id(self) -> int:
        return self._bind_helper._define_scope.id

    def _to_event_input_type(self) -> InputBindingType:
        return InputBindingType.Ref


TExprComputed = ExprComputed
