"""C1 ``VioStrategy`` Protocol (AZ-331).

PEP 544 ``typing.Protocol`` with ``runtime_checkable=True``; four
methods that span the camera-ingest hot path
(``process_frame``), F8 reboot recovery (``reset_to_warm_start``),
diagnostics (``health_snapshot``), and self-identification
(``current_strategy_label``).

Concrete impls — :class:`Okvis2Strategy` (AZ-332),
:class:`VinsMonoStrategy` (AZ-333), :class:`KltRansacStrategy`
(AZ-334) — live in sibling modules and are imported lazily by
:mod:`gps_denied_onboard.runtime_root.vio_factory`.

The contract at
``_docs/02_document/contracts/c1_vio/vio_strategy_protocol.md``
v1.0.0 is the authoritative shape; this module mirrors it 1:1.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Literal, Protocol, runtime_checkable

if TYPE_CHECKING:
    from gps_denied_onboard._types.calibration import CameraCalibration
    from gps_denied_onboard._types.nav import (
        ImuWindow,
        NavCameraFrame,
        VioHealth,
        VioOutput,
        WarmStartPose,
    )

__all__ = ["VioStrategy"]


@runtime_checkable
class VioStrategy(Protocol):
    """On-Jetson visual / visual-inertial odometry runtime.

    Implementations:
    :class:`Okvis2Strategy` (production-default, OKVIS2 SLAM),
    :class:`VinsMonoStrategy` (research-only),
    :class:`KltRansacStrategy` (mandatory simple-baseline per ADR-002).
    Selection is owned by the composition root.

    Invariants (see ``vio_strategy_protocol.md`` v1.0.0):
    - Single-threaded per instance (one camera-ingest writer thread).
    - ``current_strategy_label()`` is constant per instance and
      equals ``config.vio.strategy`` exactly.
    - Error envelope is closed — only members of
      :class:`VioError` escape ``process_frame``.
    """

    def process_frame(
        self,
        frame: "NavCameraFrame",
        imu: "ImuWindow",
        calibration: "CameraCalibration",
    ) -> "VioOutput":
        """Camera-ingest hot-path call (one per nav-camera frame).

        ``VioOutput.frame_id`` MUST equal ``frame.frame_id`` (C5
        alignment invariant). Raises :class:`VioInitializingError`
        while booting (state == INIT; no output emitted) and
        :class:`VioFatalError` once ``consecutive_lost`` exceeds the
        configured threshold. During DEGRADED operation the method
        returns normally with an inflated covariance — NOT raises
        :class:`VioDegradedError`.
        """
        ...

    def reset_to_warm_start(self, hint: "WarmStartPose") -> None:
        """Destructive re-init from an F8-reboot warm-start hint.

        Clears keyframe window, IMU integration state, feature
        tracks. Subsequent ``process_frame`` calls re-initialise from
        the hint. Raises :class:`VioFatalError` only on irrecoverable
        backend init failure.
        """
        ...

    def health_snapshot(self) -> "VioHealth":
        """Most-recent health state — FDR-stamped per the AC-NEW-3 audit."""
        ...

    def current_strategy_label(
        self,
    ) -> Literal["okvis2", "vins_mono", "klt_ransac"]:
        """Identify which concrete strategy is wired here.

        Returned string equals ``config.vio.strategy`` exactly.
        AC-NEW-3 FDR audit relies on this property.
        """
        ...
