"""L1 runtime-context Protocol definitions.

These protocols capture only the surface area actually used by ``sage-common``
base classes (``BaseService``, ``BaseFunction``).  They intentionally avoid
importing any L2+ modules so that ``sage-common`` stays a pure L1 package.

Concrete implementations (``ServiceContext``, ``TaskContext``) in
``sage-kernel`` (L3) satisfy these protocols **structurally** – no explicit
inherit/register step is needed.
"""

from __future__ import annotations

from concurrent.futures import Future
from typing import Any, Protocol, runtime_checkable


@runtime_checkable
class RuntimeContextProtocol(Protocol):
    """Minimal interface shared by all SAGE runtime contexts."""

    @property
    def logger(self) -> Any:
        """Return the logger bound to this context."""
        ...

    @property
    def name(self) -> str:
        """Return the canonical name of the runtime entity."""
        ...


@runtime_checkable
class ServiceContextProtocol(RuntimeContextProtocol, Protocol):
    """Protocol for the context injected into :class:`~sage.common.service.base_service.BaseService`.

    Only the attributes accessed inside ``BaseService`` are declared here.
    """

    @property
    def logger(self) -> Any:  # noqa: D102
        ...

    @property
    def name(self) -> str:  # noqa: D102
        ...


@runtime_checkable
class TaskContextProtocol(RuntimeContextProtocol, Protocol):
    """Protocol for the context injected into :class:`~sage.common.core.functions.base_function.BaseFunction`.

    Only the attributes / methods accessed inside ``BaseFunction`` are declared
    here.
    """

    @property
    def logger(self) -> Any:  # noqa: D102
        ...

    @property
    def name(self) -> str:  # noqa: D102
        ...

    def call_service(
        self,
        service_name: str,
        /,
        *args: Any,
        timeout: float | None = None,
        method: str | None = None,
        **kwargs: Any,
    ) -> Any:
        """Invoke a service synchronously."""
        ...

    def call_service_async(
        self,
        service_name: str,
        /,
        *args: Any,
        timeout: float | None = None,
        method: str | None = None,
        **kwargs: Any,
    ) -> Future:
        """Invoke a service asynchronously and return a :class:`~concurrent.futures.Future`."""
        ...
