from __future__ import annotations

import enum
from collections.abc import Iterator

from qroissant._config import EncodeOptions
from qroissant._message import Compression, Encoding, MessageType

class Attribute(enum.Enum):
    """q attribute applied to a value (e.g., sorted, unique, parted, grouped)."""
    NONE = ...
    SORTED = ...
    UNIQUE = ...
    PARTED = ...
    GROUPED = ...


class Shape(enum.Enum):
    """Structural shape of the q value."""
    ATOM = ...
    VECTOR = ...
    LIST = ...
    DICTIONARY = ...
    TABLE = ...
    UNARY_PRIMITIVE = ...


class Primitive(enum.Enum):
    """Underlying primitive domain of the q value."""
    BOOLEAN = ...
    GUID = ...
    BYTE = ...
    SHORT = ...
    INT = ...
    LONG = ...
    REAL = ...
    FLOAT = ...
    CHAR = ...
    SYMBOL = ...
    TIMESTAMP = ...
    MONTH = ...
    DATE = ...
    DATETIME = ...
    TIMESPAN = ...
    MINUTE = ...
    SECOND = ...
    TIME = ...
    MIXED = ...


class Type:
    """Type descriptor for a qroissant value."""
    @property
    def primitive(self) -> Primitive | None:
        """The underlying q primitive, or None if mixed."""
        ...
    @property
    def shape(self) -> Shape:
        """The structural shape of the value."""
        ...
    @property
    def attribute(self) -> Attribute | None:
        """The q attribute applied to the value, if any."""
        ...
    @property
    def sorted(self) -> bool | None:
        """Whether the value is sorted."""
        ...


class Value:
    """Base class for decoded qroissant wrapper objects."""
    @property
    def qtype(self) -> Type:
        """The full q type descriptor."""
        ...
    @property
    def primitive(self) -> Primitive | None:
        """The underlying q primitive, or None if mixed."""
        ...
    @property
    def shape(self) -> Shape:
        """The structural shape of the value."""
        ...
    @property
    def attribute(self) -> Attribute | None:
        """The q attribute applied to the value, if any."""
        ...
    def serialize(
        self,
        *,
        options: EncodeOptions | None = None,
        encoding: Encoding = ...,
        message_type: MessageType = ...,
        compression: Compression = ...,
    ) -> bytes:
        """Serialize the value into a q IPC frame.

        Parameters
        ----------
        options : EncodeOptions | None, optional
            Arrow-to-q encoding hints. When omitted, the default encoding
            policy is used.
        encoding : Encoding, default=Encoding.LITTLE_ENDIAN
            Endianness of the generated IPC payload.
        message_type : MessageType, default=MessageType.ASYNCHRONOUS
            IPC message type tag written into the frame header.
        compression : Compression, default=Compression.UNCOMPRESSED
            Compression mode applied to the payload.

        Returns
        -------
        bytes
            Encoded q IPC payload.
        """
        ...


class Atom(Value):
    """Scalar q value (e.g., integer, float, symbol)."""
    def as_py(self) -> object:
        """Convert the atom to a native Python type."""
        ...
    @property
    def value(self) -> object:
        """The atom's native Python value (equivalent to ``as_py()``)."""
        ...
    def is_null(self) -> bool:
        """Return ``True`` if this atom holds the q null sentinel for its type."""
        ...
    def is_infinite(self) -> bool:
        """``True`` if this atom is a q infinity sentinel (±∞)."""
        ...
    def __arrow_c_array__(
        self, requested_schema: object | None = None, /
    ) -> object:
        """Export the atom as an Arrow array via the PyCapsule Protocol."""
        ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...


class Vector(Value):
    """Homogeneous q list of primitive values."""
    def __len__(self) -> int:
        """Return the length of the vector."""
        ...
    def __iter__(self) -> Iterator[object]:
        """Iterate over the elements of the vector."""
        ...
    def __getitem__(self, index: int, /) -> object:
        """Get an element by index."""
        ...
    def to_list(self) -> list[object]:
        """Convert the vector to a Python list."""
        ...
    def __arrow_c_array__(
        self, requested_schema: object | None = None, /
    ) -> object:
        """Export the vector as an Arrow array via the PyCapsule Protocol."""
        ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...


class List(Value):
    """Heterogeneous/mixed q list of general values."""
    def __len__(self) -> int:
        """Return the length of the list."""
        ...
    def __iter__(self) -> Iterator[Value]:
        """Iterate over the elements of the list."""
        ...
    def __getitem__(self, index: int, /) -> Value:
        """Get an element by index."""
        ...
    def to_list(self) -> list[Value]:
        """Convert the list to a Python list of values."""
        ...
    def __arrow_c_array__(
        self, requested_schema: object | None = None, /
    ) -> object:
        """Export the list as an Arrow array via the PyCapsule Protocol."""
        ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...


class Dictionary(Value):
    """q dictionary mapping keys to values."""
    @property
    def keys(self) -> Value:
        """The dictionary keys."""
        ...
    @property
    def values(self) -> Value:
        """The dictionary values."""
        ...
    def __len__(self) -> int:
        """Return the number of key-value pairs."""
        ...
    def __arrow_c_array__(
        self, requested_schema: object | None = None, /
    ) -> object:
        """Export the dictionary as an Arrow StructArray via the PyCapsule Protocol."""
        ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...


class Table(Value):
    """q table representing tabular data."""
    @property
    def columns(self) -> list[str]:
        """The column names."""
        ...
    @property
    def num_rows(self) -> int:
        """The number of rows."""
        ...
    @property
    def num_columns(self) -> int:
        """The number of columns."""
        ...
    def column(self, name: str, /) -> Value:
        """Get a column by name."""
        ...
    def __arrow_c_stream__(
        self, requested_schema: object | None = None, /
    ) -> object:
        """Export the table as an Arrow stream via the PyCapsule Protocol."""
        ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
