from __future__ import annotations

import enum

from qroissant._values import Attribute, Primitive, Shape

class Endpoint:
    """Connection destination configuration for a q process.

    Notes
    -----
    An endpoint describes how to connect to a q process, including the transport
    protocol (TCP or Unix socket), address, and authentication credentials.
    """

    @staticmethod
    def tcp(
        host: str,
        port: int,
        *,
        username: str | None = None,
        password: str | None = None,
        timeout_ms: int | None = None,
    ) -> Endpoint:
        """Create a TCP endpoint configuration.

        Parameters
        ----------
        host : str
            Hostname or IP address of the q process.
        port : int
            TCP port exposed by the q process.
        username : str | None, optional
            Username used during the q IPC handshake.
        password : str | None, optional
            Password used during the q IPC handshake.
        timeout_ms : int | None, optional
            Connection timeout in milliseconds.

        Returns
        -------
        Endpoint
            TCP endpoint configuration.
        """
        ...

    @staticmethod
    def unix(
        path: str,
        *,
        username: str | None = None,
        password: str | None = None,
        timeout_ms: int | None = None,
    ) -> Endpoint:
        """Create a Unix-domain socket endpoint configuration.

        Parameters
        ----------
        path : str
            Filesystem path to the q Unix domain socket.
        username : str | None, optional
            Username used during the q IPC handshake.
        password : str | None, optional
            Password used during the q IPC handshake.
        timeout_ms : int | None, optional
            Connection timeout in milliseconds.

        Returns
        -------
        Endpoint
            Unix domain socket endpoint configuration.
        """
        ...

    @property
    def scheme(self) -> str:
        """The transport scheme ('tcp' or 'unix')."""
        ...
    @property
    def host(self) -> str | None:
        """The hostname, if applicable."""
        ...
    @property
    def port(self) -> int | None:
        """The port, if applicable."""
        ...
    @property
    def path(self) -> str | None:
        """The socket path, if applicable."""
        ...
    @property
    def username(self) -> str | None:
        """The configured username."""
        ...
    @property
    def password(self) -> str | None:
        """The configured password."""
        ...
    @property
    def timeout_ms(self) -> int | None:
        """The connection timeout in milliseconds."""
        ...


class PoolOptions:
    """Connection pool configuration shared by sync and async pool types.

    Parameters
    ----------
    max_size : int, default=10
        Maximum number of connections managed by the pool.
    min_idle : int | None, optional
        Minimum number of idle connections to retain when the pool is warmed.
    checkout_timeout_ms : int, default=30000
        Maximum time spent waiting for a pooled connection checkout.
    idle_timeout_ms : int | None, optional
        Maximum idle lifetime for an unused pooled connection.
    max_lifetime_ms : int | None, optional
        Maximum total lifetime for a pooled connection.
    test_on_checkout : bool, default=True
        Whether connections should be validated before they are handed out.
    healthcheck_query : str | None, default="::"
        Optional q expression used to validate live pooled connections.
        Set to ``None`` to disable active q health checks.
    retry_attempts : int, default=0
        Number of retry attempts after the initial pooled query failure.
    retry_backoff_ms : int, default=0
        Delay between retry attempts, expressed in milliseconds.
    """

    def __init__(
        self,
        *,
        max_size: int = 10,
        min_idle: int | None = None,
        checkout_timeout_ms: int = 30_000,
        idle_timeout_ms: int | None = None,
        max_lifetime_ms: int | None = None,
        test_on_checkout: bool = True,
        healthcheck_query: str | None = "::",
        retry_attempts: int = 0,
        retry_backoff_ms: int = 0,
    ) -> None: ...
    @property
    def max_size(self) -> int:
        """Configured maximum number of connections managed by the pool."""
        ...
    @property
    def min_idle(self) -> int | None:
        """Configured minimum number of idle connections to retain."""
        ...
    @property
    def checkout_timeout_ms(self) -> int:
        """Configured maximum wait time for a connection checkout, in milliseconds."""
        ...
    @property
    def idle_timeout_ms(self) -> int | None:
        """Configured maximum idle lifetime for an unused connection, in milliseconds."""
        ...
    @property
    def max_lifetime_ms(self) -> int | None:
        """Configured maximum total lifetime for a connection, in milliseconds."""
        ...
    @property
    def test_on_checkout(self) -> bool:
        """Whether connections are validated before being handed out."""
        ...
    @property
    def healthcheck_query(self) -> str | None:
        """q expression used to validate live pooled connections, or ``None`` to disable."""
        ...
    @property
    def retry_attempts(self) -> int:
        """Number of retry attempts after the initial pooled query failure."""
        ...
    @property
    def retry_backoff_ms(self) -> int:
        """Delay between retry attempts, in milliseconds."""
        ...


class SymbolInterpretation(enum.Enum):
    """Arrow representation used for q symbols."""
    UTF8 = ...
    LARGE_UTF8 = ...
    UTF8_VIEW = ...
    DICTIONARY = ...
    RAW_BYTES = ...


class ListInterpretation(enum.Enum):
    """Arrow representation used for q lists."""
    LIST = ...
    LARGE_LIST = ...
    LIST_VIEW = ...


class StringInterpretation(enum.Enum):
    """Arrow representation used for q char data."""
    UTF8 = ...
    BINARY = ...


class UnionMode(enum.Enum):
    """Arrow union representation used for mixed general lists."""
    DENSE = ...
    SPARSE = ...


class DecodeOptions:
    """Deserialization and Arrow conversion options.

    Notes
    -----
    Construct instances through :meth:`builder` and finish with
    :meth:`DecodeOptionsBuilder.build`.
    """

    @staticmethod
    def builder() -> DecodeOptionsBuilder:
        """Create a builder initialized with qroissant's default options."""
        ...
    @property
    def list_interpretation(self) -> ListInterpretation:
        """Arrow container type used when projecting q lists."""
        ...
    @property
    def union_mode(self) -> UnionMode:
        """Arrow union encoding used for mixed general lists."""
        ...
    @property
    def string_interpretation(self) -> StringInterpretation:
        """Arrow type used when projecting q char vectors."""
        ...
    @property
    def symbol_interpretation(self) -> SymbolInterpretation:
        """Arrow type used when projecting q symbol vectors and atoms."""
        ...
    @property
    def assume_symbol_utf8(self) -> bool:
        """Whether q symbols are assumed to be valid UTF-8."""
        ...
    @property
    def parallel(self) -> bool:
        """Whether table columns are decoded in parallel using multiple threads."""
        ...
    @property
    def preserve_original_body(self) -> bool:
        """Whether the raw IPC payload bytes are retained on the decoded value."""
        ...
    @property
    def validate_compressed_trailing_bytes(self) -> bool:
        """Whether trailing zero bytes after LZW-decompressed output are validated."""
        ...
    @property
    def temporal_nulls(self) -> bool:
        """Whether temporal null sentinels are mapped to ``None`` in Arrow arrays."""
        ...
    @property
    def treat_infinity_as_null(self) -> bool:
        """Whether ±∞ sentinels are mapped to ``None`` in Arrow arrays."""
        ...
    @property
    def coalesce_temporals(self) -> bool:
        """Whether heterogeneous all-temporal lists are flattened to ``Timestamp(ns)``
        instead of being emitted as Arrow ``Union``.  Use this when the
        downstream consumer (e.g. Polars) cannot ingest ``Union`` types.
        Lossy: mixed precisions are promoted to nanoseconds.
        """
        ...


class DecodeOptionsBuilder:
    """Builder for :class:`DecodeOptions`."""

    def with_list_interpretation(
        self, value: ListInterpretation, /
    ) -> DecodeOptionsBuilder:
        """Set the Arrow container type for q list projection."""
        ...
    def with_union_mode(self, value: UnionMode, /) -> DecodeOptionsBuilder:
        """Set the Arrow union encoding for mixed general lists."""
        ...
    def with_string_interpretation(
        self, value: StringInterpretation, /
    ) -> DecodeOptionsBuilder:
        """Set the Arrow type for q char vector projection."""
        ...
    def with_symbol_interpretation(
        self, value: SymbolInterpretation, /
    ) -> DecodeOptionsBuilder:
        """Set the Arrow type for q symbol projection."""
        ...
    def with_assume_symbol_utf8(self, value: bool, /) -> DecodeOptionsBuilder:
        """Set whether q symbols are assumed to be valid UTF-8."""
        ...
    def with_parallel(self, value: bool, /) -> DecodeOptionsBuilder:
        """Set whether table columns are decoded in parallel."""
        ...
    def with_preserve_original_body(self, value: bool, /) -> DecodeOptionsBuilder:
        """Set whether the raw IPC payload bytes are retained on decoded values."""
        ...
    def with_validate_compressed_trailing_bytes(
        self, value: bool, /
    ) -> DecodeOptionsBuilder:
        """Set whether trailing zero bytes after LZW decompression are validated."""
        ...
    def with_temporal_nulls(self, value: bool, /) -> DecodeOptionsBuilder:
        """Set whether temporal null sentinels are mapped to ``None`` in Arrow arrays."""
        ...
    def with_treat_infinity_as_null(self, value: bool, /) -> DecodeOptionsBuilder:
        """Set whether ±∞ sentinels are mapped to ``None`` in Arrow arrays."""
        ...
    def with_coalesce_temporals(self, value: bool, /) -> DecodeOptionsBuilder:
        """Set whether heterogeneous all-temporal lists are flattened to
        ``Timestamp(ns)`` instead of being emitted as Arrow ``Union``.

        Set to ``True`` for consumers (e.g. Polars) that reject Arrow union
        types.  Lossy: mixed precisions are promoted to nanoseconds.  Default
        ``False`` (faithful ``Union`` representation).
        """
        ...
    def build(self) -> DecodeOptions:
        """Finalize the builder into an immutable :class:`DecodeOptions` instance."""
        ...


class EncodeField:
    """q serialization hints for a single Arrow value or table column."""

    @staticmethod
    def builder() -> EncodeFieldBuilder:
        """Create a builder initialized with empty serialization hints."""
        ...
    @property
    def primitive(self) -> Primitive | None:
        """Forced q primitive type for this field, or ``None`` to infer."""
        ...
    @property
    def shape(self) -> Shape | None:
        """Forced q structural shape for this field, or ``None`` to infer."""
        ...
    @property
    def attribute(self) -> Attribute | None:
        """q attribute to apply to this field, or ``None`` for no attribute."""
        ...
    @property
    def sorted(self) -> bool | None:
        """Whether this field is sorted, or ``None`` to infer from the attribute."""
        ...


class EncodeFieldBuilder:
    """Builder for :class:`EncodeField`."""

    def with_primitive(self, value: Primitive, /) -> EncodeFieldBuilder:
        """Force the q primitive type for this field."""
        ...
    def with_shape(self, value: Shape, /) -> EncodeFieldBuilder:
        """Force the q structural shape for this field."""
        ...
    def with_attribute(self, value: Attribute, /) -> EncodeFieldBuilder:
        """Set the q attribute to apply to this field."""
        ...
    def with_sorted(self, value: bool, /) -> EncodeFieldBuilder:
        """Set whether this field is sorted."""
        ...
    def build(self) -> EncodeField:
        """Finalize the builder into immutable per-field encoding hints."""
        ...


class EncodeOptions:
    """Encoding options for Arrow-backed :func:`qroissant.encode` calls.

    Notes
    -----
    qroissant resolves Arrow inputs in the following order:

    1. qroissant metadata embedded on the Arrow field or schema
    2. per-field overrides attached through :meth:`EncodeOptionsBuilder.with_field`
    3. global defaults on :class:`EncodeOptions`
    4. generic Arrow type inference
    """

    @staticmethod
    def builder() -> EncodeOptionsBuilder:
        """Create a builder initialized with qroissant's default encoding policy."""
        ...
    @property
    def primitive(self) -> Primitive | None:
        """Global fallback q primitive type, or ``None`` to infer per-field."""
        ...
    @property
    def shape(self) -> Shape | None:
        """Global fallback q structural shape, or ``None`` to infer per-field."""
        ...
    @property
    def attribute(self) -> Attribute | None:
        """Global fallback q attribute, or ``None`` for no attribute."""
        ...
    @property
    def strict(self) -> bool:
        """Whether unknown Arrow types raise an error instead of being inferred."""
        ...
    def field(self, name: str, /) -> EncodeField | None:
        """Return per-field encoding hints for the given column name, if any."""
        ...


class EncodeOptionsBuilder:
    """Builder for :class:`EncodeOptions`."""

    def with_primitive(self, value: Primitive, /) -> EncodeOptionsBuilder:
        """Set the global fallback q primitive type."""
        ...
    def with_shape(self, value: Shape, /) -> EncodeOptionsBuilder:
        """Set the global fallback q structural shape."""
        ...
    def with_attribute(self, value: Attribute, /) -> EncodeOptionsBuilder:
        """Set the global fallback q attribute."""
        ...
    def with_strict(self, value: bool, /) -> EncodeOptionsBuilder:
        """Set whether unknown Arrow types raise an error instead of being inferred."""
        ...
    def with_field(
        self, name: str, field: EncodeField, /
    ) -> EncodeOptionsBuilder:
        """Attach per-field encoding hints for the given column name."""
        ...
    def build(self) -> EncodeOptions:
        """Finalize the builder into immutable Arrow-to-q encoding options."""
        ...
