# fmt: off

from collections.abc import Iterable
from typing import TYPE_CHECKING, Any

__all__ = [
    'AbstractRepl',
]


################################################################################

if TYPE_CHECKING:
    from .repl_alias import Scope, VarKeys, Vars
    from .repl_eval_data import ReplEvaluationData
    from .repl_eval_info import ReplEvaluationInfo

################################################################################

# TODO: make this either an ABC or a Protocol
# TODO: remove everything except `run_code_summary`, `initialize`, and `reset`.

class AbstractRepl:
    """
    Abstract interface, of which `repl.Repl` is the actual implementation.

    This delineates what `warp` requires of the repl.
    """

    def reset(self) -> None: ...
    def initialize(self, *, local_vars: 'Vars | None', global_vars: 'Vars | None', hidden_vars: 'VarKeys') -> Any: ...
    def set_logging(self, level: int, /) -> None: ...

    def get_last_exception(self) -> BaseException: ...
    def get_last_return_value(self) -> object: ...

    def get_var(self, scope: 'Scope', key: str, /) -> Any: ...
    def set_var(self, scope: 'Scope', key: str, val: Any, /) -> Any: ...
    def has_var(self, scope: 'Scope', key: str) -> bool: ...
    def del_var(self, scope: 'Scope', key: str) -> bool: ...
    def dir_vars(self, scope: 'Scope', /) -> list[str]: ...

    # def run_on_var(self, scope: 'Scope', key: str, fn: Callable[[Any], Any], /) -> Any: ...

    def clear_vars(self, scope: 'Scope', /) -> None: ...
    def hide_vars(self, keys: Iterable[str], /) -> None: ...
    def set_vars(self, scope: 'Scope', rec: 'Vars') -> None: ...

    def run_code(self, source: str) -> 'ReplEvaluationData': ...
    def run_code_info(self, source: str, **options) -> 'ReplEvaluationInfo': ...

    async def async_run_code(self, source: str) -> 'ReplEvaluationData': ...
    async def async_run_code_info(self, source: str, **options) -> 'ReplEvaluationInfo': ...
