"""Fresh observer namespace manual and natural-timer choreography."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol

from .contract import OBSERVER_NAMESPACE


class ObserverError(RuntimeError):
    """Observer evidence does not prove the required linked PASS pair."""


@dataclass(frozen=True, slots=True)
class ObserverHead:
    """One authenticated observer chain head."""

    digest: str
    status: str
    previous_digest: str
    failures: tuple[str, ...]
    namespace: str
    timer_invocation_id: str | None = None


class TimerSubscription(Protocol):
    """Exact pre-armed natural timer event subscription."""

    def await_pass(self) -> ObserverHead: ...


class ObserverControl(Protocol):
    """Injected observer transaction boundary; production adapter is separately sealed."""

    def fence_timer_and_capture_failed_head(self) -> ObserverHead: ...

    def run_manual(self, previous: ObserverHead) -> ObserverHead: ...

    def subscribe_timer(self, previous: ObserverHead) -> TimerSubscription: ...

    def restore_timer(self) -> None: ...


def require_pass(head: ObserverHead, previous: ObserverHead, *, natural: bool) -> None:
    """Require a fresh linked PASS and timer corroboration when natural."""
    if (
        head.namespace != OBSERVER_NAMESPACE
        or head.status != "PASS"
        or head.failures
        or head.previous_digest != previous.digest
    ):
        raise ObserverError("observer link")
    if natural and head.timer_invocation_id is None:
        raise ObserverError("natural timer evidence")
