"""Primitive serialization helpers."""

import base64
from collections.abc import Mapping
from dataclasses import fields, is_dataclass
from datetime import date, datetime, time
from datetime import timezone as utc_timezone
from decimal import Decimal
from enum import Enum
from pathlib import Path
from typing import Any
from uuid import UUID
from zoneinfo import ZoneInfo

from pydantic import BaseModel


class Serializer:
    """Convert values to JSON-safe primitives."""

    def to_primitive(self, value: Any) -> Any:
        if is_dataclass(value):
            return {field.name: self.to_primitive(getattr(value, field.name)) for field in fields(value)}
        if isinstance(value, BaseModel):
            return {key: self.to_primitive(item) for key, item in value.model_dump().items()}
        if isinstance(value, datetime):
            if value.tzinfo is not None:
                return value.astimezone(utc_timezone.utc).isoformat().replace("+00:00", "Z")
            return value.isoformat()
        if isinstance(value, date | time):
            return value.isoformat()
        if isinstance(value, Mapping):
            return {str(self.to_primitive(key)): self.to_primitive(item) for key, item in value.items()}
        if isinstance(value, (list, tuple, set, frozenset)):
            return [self.to_primitive(item) for item in value]
        if isinstance(value, Enum):
            return self.to_primitive(value.value)
        if isinstance(value, Decimal):
            return str(value)
        if isinstance(value, UUID | Path):
            return str(value)
        if isinstance(value, ZoneInfo):
            return getattr(value, "key", str(value))
        if isinstance(value, bytes | bytearray):
            return base64.b64encode(bytes(value)).decode("ascii")
        return value


_default_serializer = Serializer()


def to_primitive(value: Any) -> Any:
    """Serialize a value with the default serializer."""

    return _default_serializer.to_primitive(value)


def asdict_primitives(value: Any) -> Any:
    """Backward-compatible alias for primitive serialization."""

    return to_primitive(value)


__all__ = ["Serializer", "asdict_primitives", "to_primitive"]
