"""Composition-root :class:`Clock` factory (AZ-398).

Composition resolves :class:`Clock` exactly once per process per
Invariant — Single Clock per process. Live / research / operator
binaries call :func:`build_clock(kind="wall")`; the replay binary
calls :func:`build_clock(kind="tlog", source=...)` (the replay
composition root, AZ-401, wires the tlog timestamp source).

Concrete strategy modules (``wall_clock``, ``tlog_derived``) live
under :mod:`gps_denied_onboard.clock`; they are imported eagerly here
because the Clock has no Tier-specific runtime dependency and the
selection happens at startup.
"""

from __future__ import annotations

from collections.abc import Callable, Iterable
from typing import TYPE_CHECKING

from gps_denied_onboard.clock.tlog_derived import TlogDerivedClock
from gps_denied_onboard.clock.wall_clock import WallClock

if TYPE_CHECKING:
    from gps_denied_onboard.clock import Clock


__all__ = ["build_clock"]


def build_clock(
    *,
    kind: str = "wall",
    source: Callable[[], int] | Iterable[int] | None = None,
) -> "Clock":
    """Construct the :class:`Clock` strategy for this process.

    ``kind`` is one of ``"wall"`` (default) or ``"tlog"``. ``source`` is
    required when ``kind == "tlog"`` (it carries the tlog parser's
    timestamp stream) and forbidden otherwise.

    Raises :class:`ValueError` on an unknown ``kind`` or a misconfigured
    source — neither is recoverable, so failing loudly at composition
    time is correct.
    """
    if kind == "wall":
        if source is not None:
            raise ValueError(
                "build_clock(kind='wall'): source must be None; "
                "WallClock takes no upstream timestamp stream."
            )
        return WallClock()
    if kind == "tlog":
        if source is None:
            raise ValueError(
                "build_clock(kind='tlog'): source is required (the tlog "
                "timestamp stream from the replay parser)."
            )
        return TlogDerivedClock(source)
    raise ValueError(
        f"build_clock: unknown kind {kind!r}; expected 'wall' or 'tlog'"
    )
