from typing import Any, Callable, Generic, Iterator, TypeVar

class Snapshot:
    """A snapshot of a document's state at a given point in time."""

    @staticmethod
    def from_doc(doc: "Doc") -> "Snapshot":
        """Create a snapshot from a document."""

    @staticmethod
    def decode(data: bytes) -> "Snapshot":
        """Decode a snapshot from its binary representation."""

    def encode(self) -> bytes:
        """Encode the snapshot to its binary representation."""

class Doc:
    """Shared document."""

    def __init__(self, client_id: int | None, skip_gc: bool | None) -> None:
        """Create a new document with an optional global client ID.
        If no client ID is passed, a random one will be generated."""

    @staticmethod
    def from_snapshot(snapshot: "Snapshot", doc: Doc) -> "Doc":
        """Create a new Doc from a Snapshot and an original Doc."""

    def client_id(self) -> int:
        """Returns the document unique client identifier."""

    def guid(self) -> int:
        """Returns the document globally unique identifier."""

    def create_transaction(self) -> Transaction:
        """Create a document transaction."""

    def create_transaction_with_origin(self, origin: Any) -> Transaction:
        """Create a document transaction with an origin."""

    def get_or_insert_text(self, txn: Transaction, name: str) -> Text:
        """Create a text root type on this document, or get an existing one."""

    def get_or_insert_array(self, txn: Transaction, name: str) -> Array:
        """Create an array root type on this document, or get an existing one."""

    def get_or_insert_map(self, txn: Transaction, name: str) -> Map:
        """Create a map root type on this document, or get an existing one."""

    def get_or_insert_xml_fragment(self, txn: Transaction, name: str) -> XmlFragment:
        """Create an XML fragment root type on this document, or get an existing one."""

    def get_state(self, txn: Transaction) -> bytes:
        """Get the current document state."""

    def get_update(self, txn: Transaction, state: bytes) -> bytes:
        """Get the update from the given state to the current state."""

    def apply_update(self, txn: Transaction, update: bytes) -> None:
        """Apply the update to the document."""

    def roots(self, txn: Transaction) -> dict[str, Text | Array | Map]:
        """Get top-level (root) shared types available in current document."""

    def observe(self, callback: Callable[[TransactionEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the shared document change event.
        Returns a subscription that can be used to unsubscribe."""

    def observe_subdocs(self, callback: Callable[[SubdocsEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the shared document subdoc change event.
        Returns a subscription that can be used to unsubscribe."""

class Subscription:
    """Observer subscription."""

    def drop(self) -> None:
        """Drops the subscription, effectively unobserving."""

class Transaction:
    """Document transaction"""

    def drop(self) -> None:
        """Drop the transaction, effectively committing document changes."""

    def commit(self) -> None:
        """Commit the document changes."""

    @property
    def origin(self) -> Any:
        """The origin of the transaction."""

class TransactionEvent:
    """
    Event generated by the [observe][pycrdt.Doc.observe] method,
    emitted during the transaction commit phase.
    """

    @property
    def update(self) -> bytes:
        """The emitted binary update."""

class SubdocsEvent:
    """
    Event generated by the [observe_subdocs][pycrdt.Doc.observe_subdocs] method,
    emitted during the transaction commit phase."""

class TextEvent:
    """Event generated by `Text.observe` method. Emitted during transaction commit
    phase."""

class ArrayEvent:
    """Event generated by `Array.observe` method. Emitted during transaction commit
    phase."""

class MapEvent:
    """Event generated by `Map.observe` method. Emitted during transaction commit
    phase."""

class XmlEvent:
    """Event generated by `Xml*.observe` methods. Emitted during transaction commit
    phase."""

class Text:
    """Shared text."""

    def len(self, txn: Transaction) -> int:
        """Returns the number of characters visible in the current shared text."""

    def insert(
        self,
        txn: Transaction,
        index: int,
        chunk: str,
        attrs: Iterator[tuple[str, Any]] | None = None,
    ) -> None:
        """Inserts a `chunk` of text at a given `index`, with optional attributes."""

    def insert_embed(
        self,
        txn: Transaction,
        index: int,
        embed: Any,
        attrs: Iterator[tuple[str, Any]] | None = None,
    ) -> None:
        """Inserts an embed at a given `index`, with optional attributes."""

    def format(
        self, txn: Transaction, index: int, len: int, attrs: Iterator[tuple[str, Any]]
    ) -> None:
        """Formats a range of elements."""

    def remove_range(self, txn: Transaction, index: int, len: int) -> None:
        """Removes up to `len` characters from th current shared text, starting at
        given`index`."""

    def get_string(self, txn: Transaction) -> str:
        """Returns a text representation of the current shared text."""

    def diff(self, txn: Transaction) -> list[tuple[Any, dict[str, Any] | None]]:
        """Returns a sequence of formatted chunks."""

    def observe(self, callback: Callable[[TextEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the shared text change event.
        Returns a subscription that can be used to unsubscribe."""

    def unobserve(self, subscription: Subscription) -> None:
        """Unsubscribes previously subscribed event callback identified by given
        `subscription`."""

class Array:
    """Shared array."""

    def len(self, txn: Transaction) -> int:
        """Returns the number of elements in the current array."""

    def insert(self, txn: Transaction, index: int, value: Any) -> None:
        """Inserts `value` at the given `index`."""

    def move_to(self, txn: Transaction, source: int, target: int) -> None:
        """Moves element found at `source` index into `target` index position.."""

    def remove_range(self, txn: Transaction, index: int, len: int) -> None:
        """Removes 'len' elements starting at provided `index`."""

    def get(self, txn: Transaction, index: int) -> Any:
        """Retrieves a value stored at a given `index`."""

    def to_json(self, txn: Transaction) -> str:
        """Returns a JSON representation of the current array."""

    def observe(self, callback: Callable[[TextEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the array change event.
        Returns a subscription that can be used to unsubscribe."""

    def observe_deep(self, callback: Callable[[TextEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the array change event
        and its nested elements.
        Returns a subscription that can be used to unsubscribe."""

    def unobserve(self, subscription: Subscription) -> None:
        """Unsubscribes previously subscribed event callback identified by given
        `subscription`."""

class Map:
    """Shared map."""

    def len(self, txn: Transaction) -> int:
        """Returns a number of characters visible in a current text data structure."""

    def insert(self, txn: Transaction, key: str, value: Any) -> None:
        """Inserts `value` at the given `key`."""

    def remove(self, txn: Transaction, key: str) -> None:
        """Removes the `key` entry."""

    def get(self, txn: Transaction, key: str) -> Any:
        """Retrieves a value stored under a given `key`."""

    def to_json(self, txn: Transaction) -> str:
        """Returns a JSON representation of the current map."""

    def observe(self, callback: Callable[[TextEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the map change event.
        Returns a subscription that can be used to unsubscribe."""

    def observe_deep(self, callback: Callable[[TextEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the map change event
        and its nested elements.
        Returns a subscription that can be used to unsubscribe."""

    def unobserve(self, subscription: Subscription) -> None:
        """Unsubscribes previously subscribed event callback identified by given
        `subscription`."""

    def has(self, txn: Transaction, key: str) -> bool:
        """Returns true if the given key exists in the map."""

class XmlFragment:
    def parent(self) -> XmlFragment | XmlElement | XmlText | None:
        """Returns the parent of the XML fragment, if any."""

    def get_string(self, txn: Transaction) -> str:
        """Returns a text representation of the current shared XML."""

    def len(self, txn: Transaction) -> int:
        """Returns the numer of children of the current shared XML."""

    def get(self, txn: Transaction, index: int) -> XmlFragment | XmlElement | XmlText | None:
        """Gets a child item by index, or `None` if the index is out of bounds."""

    def remove_range(self, txn: Transaction, index: int, len: int) -> None:
        """Removes a range of children."""

    def insert_str(self, txn: Transaction, index: int, text: str) -> XmlText:
        """Inserts a text node."""

    def insert_element_prelim(self, txn: Transaction, index: int, tag: str) -> XmlElement:
        """Inserts an empty element node at given index, and returns it."""

    def observe(self, callback: Callable[[XmlEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the XML change event.
        Returns a subscription that can be used to unsubscribe."""

    def observe_deep(self, callback: Callable[[XmlEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the XML change event
        and its nested elements.
        Returns a subscription that can be used to unsubscribe."""

class XmlElement:
    def parent(self) -> XmlFragment | XmlElement | XmlText | None:
        """Returns the parent of the XML element, if any."""

    def get_string(self, txn: Transaction) -> str:
        """Returns a text representation of the current shared XML."""

    def len(self, txn: Transaction) -> int:
        """Returns the numer of children of the current shared XML."""

    def get(self, txn: Transaction, index: int) -> XmlFragment | XmlElement | XmlText | None:
        """Gets a child item by index, or `None` if the index is out of bounds."""

    def remove_range(self, txn: Transaction, index: int, len: int) -> None:
        """Removes a range of children."""

    def insert_str(self, txn: Transaction, index: int, text: str) -> XmlText:
        """Inserts a text node."""

    def insert_element_prelim(self, txn: Transaction, index: int, tag: str) -> XmlElement:
        """Inserts an empty element node at a given index, and returns it."""

    def attributes(self, txn: Transaction) -> list[tuple[str, str]]:
        """Gets all attributes, as a list of `(key, value)` tuples."""

    def attribute(self, txn: Transaction, name: str) -> str | None:
        """Gets an attribute, or `None` if the attribute does not exist."""

    def insert_attribute(self, txn: Transaction, name: str, value: str) -> None:
        """Inserts or overwrites an attribute."""

    def remove_attribute(self, txn: Transaction, name: str) -> None:
        """Removes an attribute."""

    def siblings(self, txn) -> list[XmlFragment | XmlElement | XmlText]:
        """Gets the siblings of this node."""

    def observe(self, callback: Callable[[XmlEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the XML change event.
        Returns a subscription that can be used to unsubscribe."""

    def observe_deep(self, callback: Callable[[XmlEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the XML change event
        and its nested elements.
        Returns a subscription that can be used to unsubscribe."""

class XmlText:
    def parent(self) -> XmlFragment | XmlElement | XmlText | None:
        """Returns the XML text parent, if any."""

    def get_string(self, txn: Transaction) -> str:
        """Returns a text representation of the current shared XML."""

    def attributes(self, txn: Transaction) -> list[tuple[str, str]]:
        """Gets all attributes, as a list of `(key, value)` tuples."""

    def attribute(self, txn: Transaction, name: str) -> str | None:
        """Gets an attribute, or `None` if the attribute does not exist."""

    def insert_attribute(self, txn: Transaction, name: str, value: str) -> None:
        """Inserts or overwrites an attribute."""

    def remove_attribute(self, txn: Transaction, name: str) -> None:
        """Removes an attribute."""

    def siblings(self, txn: Transaction) -> list[XmlFragment | XmlElement | XmlText]:
        """Gets the siblings of this node."""

    def insert(
        self,
        txn: Transaction,
        index: int,
        text: str,
        attrs: Iterator[tuple[str, Any]] | None = None,
    ):
        """Inserts text, with optional with attributes."""

    def remove_range(self, txn: Transaction, index: int, len: int):
        """Removes text."""

    def format(self, txn: Transaction, index: int, len: int, attrs: Iterator[tuple[str, Any]]):
        """Adds attributes to a section of text."""

    def diff(self, txn: Transaction) -> list[tuple[Any, dict[str, Any] | None]]:
        """Returns a sequence of formatted chunks."""

    def observe(self, callback: Callable[[XmlEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the XML change event.
        Returns a subscription that can be used to unsubscribe."""

    def observe_deep(self, callback: Callable[[XmlEvent], None]) -> Subscription:
        """Subscribes a callback to be called with the XML change event
        and its nested elements.
        Returns a subscription that can be used to unsubscribe."""

class UndoManager:
    """Undo manager."""

    def __init__(
        self,
        doc: Doc,
        capture_timeout_millis: int,
        timestamp: Callable[[], int],
        undo_stack: list[StackItem] | None = None,
        redo_stack: list[StackItem] | None = None,
    ) -> None:
        """Creates an undo manager."""

    def expand_scope(self, scope: Text | Array | Map) -> None:
        """Extends a list of shared types tracked by current undo manager by a given scope."""

    def include_origin(self, origin: int) -> None:
        """Extends a list of origins tracked by current undo manager by a given origin."""

    def exclude_origin(self, origin: int) -> None:
        """Removes an origin from the list of origins tracked by current undo manager."""

    def can_undo(self) -> bool:
        """Whether there is any change to undo."""

    def undo(self) -> bool:
        """Undo last action tracked by current undo manager."""

    def can_redo(self) -> bool:
        """Whether there is any change to redo."""

    def redo(self) -> bool:
        """Redo last action previously undone by current undo manager."""

    def clear(self) -> None:
        """Clear all items stored within current undo manager."""

    def undo_stack(self) -> list[StackItem]:
        """Returns the undo manager's undo stack."""

    def redo_stack(self) -> list[StackItem]:
        """Returns the undo manager's redo stack."""

class IdSet:
    """A set of deletions in a CRDT document."""

    def __init__(self) -> None:
        """Create a new empty IdSet."""

    def encode(self) -> bytes:
        """Encode the IdSet to bytes."""

    @staticmethod
    def decode(data: bytes) -> IdSet:
        """Decode a IdSet from bytes."""

MetaT = TypeVar("MetaT")

class StackItem(Generic[MetaT]):
    """A unit of work for the [UndoManager][pycrdt.UndoManager], consisting of
    compressed information about all updates and deletions tracked by it.
    """

    def __init__(self, deletions: IdSet, insertions: IdSet, meta: MetaT | None = None) -> None:
        """Create a new StackItem.

        Args:
            deletions: The IdSet of deletions.
            insertions: The IdSet of insertions.
            meta: Optional metadata (can be any Python object).
        """

    @property
    def deletions(self) -> IdSet:
        """Get the deletions IdSet."""

    @property
    def insertions(self) -> IdSet:
        """Get the insertions IdSet."""

    @property
    def meta(self) -> MetaT | None:
        """Custom metadata. Can be any Python object."""

    @staticmethod
    def merge(
        a: "StackItem[MetaT]",
        b: "StackItem[MetaT]",
        merge_meta: Callable[[MetaT | None, MetaT | None], Any] | None = None,
    ) -> "StackItem[Any]":
        """Merge two StackItems into one containing the union of their deletions and insertions.

        Args:
            a: First StackItem to merge.
            b: Second StackItem to merge.
            merge_meta: Optional function to handle metadata conflicts.
                Takes (meta_a, meta_b) and returns the merged metadata.
                If None, keeps the first item's metadata.
        """

class StickyIndex:
    def get_offset(self, txn: Transaction) -> int: ...
    def encode(self) -> bytes: ...
    def to_json_string(self) -> str: ...
    def get_assoc(self) -> int: ...

def merge_updates(updates: tuple[bytes, ...]) -> bytes: ...
def get_state(update: bytes) -> bytes: ...
def get_update(update: bytes, state: bytes) -> bytes: ...
def decode_sticky_index(data: bytes) -> StickyIndex: ...
def get_sticky_index_from_json_string(data: str) -> StickyIndex: ...
