from collections.abc import Sequence
from typing import Any
from typing_extensions import Self

from google._upb._message import Descriptor as _upb_Descriptor

from .descriptor import Descriptor, FieldDescriptor
from .internal.extension_dict import _ExtensionDict, _ExtensionFieldDescriptor

class Error(Exception): ...
class DecodeError(Error): ...
class EncodeError(Error): ...

class Message:
    __slots__: tuple[str, ...] = ()
    DESCRIPTOR: Descriptor | _upb_Descriptor
    def __deepcopy__(self, memo: Any = None) -> Self: ...
    def __eq__(self, other_msg: object) -> bool: ...
    def __ne__(self, other_msg: object) -> bool: ...
    def __contains__(self, field_name_or_key: str) -> bool: ...
    def MergeFrom(self, other_msg: Self) -> None: ...
    def CopyFrom(self, other_msg: Self) -> None: ...
    def Clear(self) -> None: ...
    def SetInParent(self) -> None: ...
    def IsInitialized(self) -> bool: ...
    def MergeFromString(self, serialized: bytes) -> int: ...
    def ParseFromString(self, serialized: bytes) -> int: ...
    def SerializeToString(self, *, deterministic: bool = ...) -> bytes: ...
    def SerializePartialToString(self, *, deterministic: bool = ...) -> bytes: ...
    def ListFields(self) -> Sequence[tuple[FieldDescriptor, Any]]: ...  # Any: str, int, float, bytes, bool, or Message
    # Intentionally left out typing on these three methods, because they are
    # stringly typed and it is not useful to call them on a Message directly.
    # We prefer more specific typing on individual subclasses of Message
    # See https://github.com/dropbox/mypy-protobuf/issues/62 for details
    def HasField(self, field_name: Any) -> bool: ...
    def ClearField(self, field_name: Any) -> None: ...
    def WhichOneof(self, oneof_group: Any) -> Any: ...
    def HasExtension(self, field_descriptor: _ExtensionFieldDescriptor[Self, Any]) -> bool: ...
    def ClearExtension(self, field_descriptor: _ExtensionFieldDescriptor[Self, Any]) -> None: ...
    # The TypeVar must be bound to `Message` or we get mypy errors, so we cannot use `Self` for `Extensions`
    @property
    def Extensions(self) -> _ExtensionDict[Self]: ...
    def UnknownFields(self) -> Any: ...  # Any: subclasses return UnknownFieldSet
    def DiscardUnknownFields(self) -> None: ...
    def ByteSize(self) -> int: ...
    @classmethod
    def FromString(cls, s: bytes) -> Self: ...
    # TODO: check kwargs
    def __new__(cls, *args, **kwargs) -> Self: ...
