import typing as t
import collections.abc as c

from skoll.result import Result
from skoll.application.types import *
from skoll.domain import EntityState, Message


__all__ = ["DB", "Mediator", "Authz", "Repository"]


class Mediator(t.Protocol):

    async def connect(self) -> None: ...
    async def disconnect(self) -> None: ...
    def register(self, *services: Service) -> None: ...
    async def publish(self, msg: Message | RawMessage) -> None: ...
    async def request(self, msg: Message | RawMessage) -> Result[t.Any]: ...


class Authz(t.Protocol):

    async def check(self, tuple: str, cxt: dict[str, t.Any] | None = None) -> None: ...
    async def write(
        self, changes: list[AuthzWriteChange], preconditions: list[AuthzPrecondition] | None = None
    ) -> str: ...
    async def lookup(
        self, filter: str, cxt: dict[str, t.Any] | None = None, limit: int | None = None, cursor: str | None = None
    ) -> AuthzLookupResult: ...


class Repository[T: EntityState](t.Protocol):

    async def save(self, state: T) -> None: ...
    async def delete(self, criteria: Criteria) -> None: ...
    async def exists(self, criteria: Criteria) -> bool: ...
    async def get(self, criteria: Criteria) -> T | None: ...
    async def list(self, criteria: ListCriteria) -> ListPage[T]: ...


class DB[T = t.Any](t.Protocol):

    async def close(self) -> None: ...
    async def connect(self) -> None: ...
    def session(self) -> c.AsyncGenerator[T]: ...
    def transaction(self) -> c.AsyncGenerator[T]: ...
