"""Serializer for converting sort specifications to/from compact string format.

This module provides serialization capabilities for converting sort specifications
to and from compact comma-separated string representations, suitable for use in
URL query parameters and APIs.

Format
------
Sort specifications are serialized as comma-separated lists of field criteria:
- Each criterion is a field name optionally prefixed with + (ascending) or - (descending)
- No prefix defaults to ascending

Examples
--------
>>> from therismos.sorting import SortSpec, SortCriterion, SortOrder
>>> from therismos.sorting.serializer import Serializer
>>>
>>> # Basic serialization
>>> spec = SortSpec([
...     SortCriterion("age", SortOrder.ASCENDING),
...     SortCriterion("created_at", SortOrder.DESCENDING),
... ])
>>> serializer = Serializer()
>>> text = serializer.serialize(spec)
>>> # Result: "age,-created_at"
>>>
>>> # Deserialization
>>> spec = serializer.deserialize("name,-score,+priority")
>>> # Result: SortSpec with name ASC, score DESC, priority ASC
"""

from __future__ import annotations

from therismos.sorting._sorting import SortCriterion, SortOrder, SortSpec


class Serializer:
    """Serializer for converting sort specifications to/from string format.

    Example:
        >>> serializer = Serializer()
        >>> spec = SortSpec([
        ...     SortCriterion("age", SortOrder.ASCENDING),
        ...     SortCriterion("name", SortOrder.DESCENDING),
        ... ])
        >>> text = serializer.serialize(spec)
        >>> # Result: "age,-name"
    """

    def serialize(self, spec: SortSpec) -> str:
        """Serialize a sort specification to string format.

        :param spec: The sort specification to serialize.
        :type spec: SortSpec
        :returns: Serialized string representation.
        :rtype: str

        Example:
            >>> spec = SortSpec([
            ...     SortCriterion("age", SortOrder.ASCENDING),
            ...     SortCriterion("name", SortOrder.DESCENDING),
            ... ])
            >>> serializer.serialize(spec)
            'age,-name'
        """
        parts = []

        for criterion in spec:
            # Skip NONE orders during serialization
            if criterion.order == SortOrder.NONE:
                continue

            # Build the field representation
            field_str = criterion.field

            # Add order prefix
            if criterion.order == SortOrder.DESCENDING:
                field_str = "-" + field_str

            parts.append(field_str)

        return ",".join(parts)

    def deserialize(self, text: str) -> SortSpec:
        """Deserialize a string to a sort specification.

        :param text: The serialized sort specification string.
        :type text: str
        :returns: The deserialized sort specification.
        :rtype: SortSpec
        :raises ValueError: If the string format is invalid.

        Example:
            >>> serializer.deserialize("age,-name,+score")
            SortSpec([...])  # age ASC, name DESC, score ASC
        """
        if not text or text.strip() == "":
            return SortSpec()

        criteria = []
        parts = text.split(",")

        for part in parts:
            part = part.strip()
            if not part:
                continue

            # Determine order based on prefix
            if part.startswith("-"):
                order = SortOrder.DESCENDING
                field_name = part[1:]
            elif part.startswith("+"):
                order = SortOrder.ASCENDING
                field_name = part[1:]
            else:
                order = SortOrder.ASCENDING
                field_name = part

            # Validate field name
            if not field_name:
                msg = "Field name cannot be empty"
                raise ValueError(msg)

            # Create the criterion
            criterion = SortCriterion(field_name, order)
            criteria.append(criterion)

        return SortSpec(criteria)


__all__ = [
    "Serializer",
]
