"""Routing primitives for message broker topic selection and partitioning.

Analogous to ``db_core.query.operators`` — frozen dataclasses that represent
routing decisions without coupling to any specific backend.
"""

from dataclasses import dataclass
from typing import Optional


@dataclass(frozen=True)
class TopicPattern:
    """Represents a topic subscription pattern.

    For backends that support wildcards (e.g. NATS, RabbitMQ), the pattern
    may include ``*`` or ``>`` tokens.  For Kafka, this is always an exact
    topic name.
    """

    pattern: str
    exact: bool = True

    def __str__(self) -> str:
        return self.pattern


@dataclass(frozen=True)
class PartitionTarget:
    """Target a specific partition or let the broker decide.

    ``PartitionTarget.ANY`` (the default) tells the broker to use its
    default partitioner (key-hash or round-robin).
    """

    partition: Optional[int] = None

    @classmethod
    def ANY(cls) -> "PartitionTarget":
        """Let the broker choose the partition."""
        return cls(partition=None)

    @classmethod
    def specific(cls, n: int) -> "PartitionTarget":
        """Target an explicit partition number."""
        if n < 0:
            raise ValueError("Partition number must be >= 0")
        return cls(partition=n)
