from typing import Optional, Type
from types import TracebackType
from datetime import datetime
from enum import Enum

from automerge.core import ScalarValue, Value

class Document:
    def __init__(self, actor_id: Optional[bytes] = None) -> None: ...
    def get_actor(self) -> bytes: ...
    def set_actor(self, actor_id: bytes) -> None: ...
    def transaction(self) -> Transaction: ...
    def save(self) -> bytes: ...
    @staticmethod
    def load(data: bytes) -> Document: ...
    def fork(self, heads: Optional[list[bytes]] = None) -> Document: ...
    def merge(self, other: Document) -> list[bytes]: ...
    def diff(
        self, before_heads: list[bytes], after_heads: list[bytes]
    ) -> list[Patch]: ...
    def generate_sync_message(self, state: SyncState) -> Message: ...
    def receive_sync_message(self, state: SyncState, msg: Message) -> None: ...
    def get_heads(self) -> list[bytes]: ...
    def get_last_local_change(self) -> Optional[Change]: ...
    def object_type(self, obj_id: bytes) -> ObjType: ...
    def get_changes(self, have_deps: list[bytes]) -> list[Change]: ...
    def get(
        self, obj_id: bytes, prop: str | int, heads: Optional[list[bytes]] = None
    ) -> Optional[tuple[Value, bytes]]: ...
    def keys(self, obj_id: bytes, heads: Optional[list[bytes]] = None) -> list[str]: ...
    def values(
        self, obj_id: bytes, heads: Optional[list[bytes]] = None
    ) -> list[tuple[Value, bytes]]: ...
    def length(self, obj_id: bytes, heads: Optional[list[bytes]] = None) -> int: ...
    def text(self, obj_id: bytes, heads: Optional[list[bytes]] = None) -> str: ...
    def marks(
        self, obj_id: bytes, heads: Optional[list[bytes]] = None
    ) -> list[Mark]: ...

class Transaction:
    def __enter__(self) -> Transaction: ...
    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc: Optional[BaseException],
        traceback: Optional[TracebackType],
    ) -> None: ...
    def get_heads(self) -> list[bytes]: ...
    def object_type(self, obj_id: bytes) -> ObjType: ...
    def get_changes(self, have_deps: list[bytes]) -> list[Change]: ...
    def get(
        self, obj_id: bytes, prop: str | int, heads: Optional[list[bytes]] = None
    ) -> Optional[tuple[ObjType | tuple[ScalarType, ScalarValue], bytes]]: ...
    def keys(self, obj_id: bytes, heads: Optional[list[bytes]] = None) -> list[str]: ...
    def values(
        self, obj_id: bytes, heads: Optional[list[bytes]] = None
    ) -> list[tuple[Value, bytes]]: ...
    def length(self, obj_id: bytes, heads: Optional[list[bytes]] = None) -> int: ...
    def text(self, obj_id: bytes, heads: Optional[list[bytes]] = None) -> str: ...
    # def marks
    def put(
        self,
        obj_id: bytes,
        prop: str | int,
        scalar_type: ScalarType,
        value: ScalarValue,
    ) -> None: ...
    def put_object(
        self, obj_id: bytes, prop: str | int, obj_type: ObjType
    ) -> bytes: ...
    def insert(
        self, obj_id: bytes, idx: int, scalar_type: ScalarType, value: ScalarValue
    ) -> None: ...
    def insert_object(self, obj_id: bytes, idx: int, obj_type: ObjType) -> bytes: ...
    def increment(self, obj_id: bytes, prop: str | int, amount: int) -> None: ...
    def delete(self, obj_id: bytes, prop: str | int) -> None: ...
    def mark(
        self,
        obj_id: bytes,
        start: int,
        end: int,
        name: str,
        scalar_type: ScalarType,
        value: ScalarValue,
        expand: ExpandMark,
    ) -> None: ...
    def unmark(self, obj_id: bytes, start: int, end: int, name: str) -> None: ...

class Mark:
    start: int
    end: int
    name: str
    value: tuple[ScalarType, ScalarValue]

class SyncState:
    def __init__(self) -> None: ...

class Message:
    @staticmethod
    def decode(data: bytes) -> Message: ...
    def encode(self) -> bytes: ...

class Change:
    actor_id: bytes
    other_actor_ids: list[bytes]
    def __len__(self) -> int: ...
    max_op: int
    start_op: int
    message: Optional[str]
    deps: list[bytes]
    hash: bytes
    seq: int
    timestamp: datetime
    raw_bytes: bytes
    extra_bytes: bytes
    bytes: bytes

class Patch: ...

class ObjType(Enum):
    Map: ObjType
    List: ObjType
    Text: ObjType

class ScalarType(Enum):
    Bytes: ScalarType
    Str: ScalarType
    Int: ScalarType
    Uint: ScalarType
    F64: ScalarType
    Counter: ScalarType
    Timestamp: ScalarType
    Boolean: ScalarType
    Unknown: ScalarType
    Null: ScalarType

class ExpandMark(Enum):
    Before: ExpandMark
    After: ExpandMark
    Both: ExpandMark
    Neither: ExpandMark

ROOT: bytes

def random_actor_id() -> bytes: ...
