"""C3.5 ``ConditionalRefiner`` config block (AZ-348).

Registered into ``config.components['c3_5_adhop']`` by the
package ``__init__.py``. The composition-root factory
:func:`gps_denied_onboard.runtime_root.refiner_factory.build_refiner_strategy`
reads this block to select the strategy and configure thresholds.

``strategy`` selects one of the two concrete refiners
(``adhop`` — production-default; ``passthrough`` — baseline /
smoke / IT-12 comparison). Both modules are linked
unconditionally: there is NO ``BUILD_REFINER_*`` flag (NOT ADR-002
territory). Runtime selection only.

``residual_threshold_px`` is the conditional-gate threshold: a
:class:`MatchResult` whose ``reprojection_residual_px <=
threshold`` is passed through unchanged; ``>`` invokes the
strategy's refinement procedure. Default 2.5 px (the AC-NEW-5 /
R10 tunable from operator tooling).

``invocation_rate_warn_threshold`` is the rolling-60 s
invocation-rate ceiling above which a WARN log fires
(C3.5-IT-03 / NFT-PERF-01). Must be in ``(0, 1)``; default 0.25.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Final

from gps_denied_onboard.config.schema import ConfigError

__all__ = [
    "C3_5RefinerConfig",
    "KNOWN_STRATEGIES",
]


KNOWN_STRATEGIES: Final[frozenset[str]] = frozenset({"adhop", "passthrough"})


@dataclass(frozen=True)
class C3_5RefinerConfig:
    """Per-component config for C3.5 conditional refiner."""

    strategy: str = "adhop"
    residual_threshold_px: float = 2.5
    invocation_rate_warn_threshold: float = 0.25

    def __post_init__(self) -> None:
        if self.strategy not in KNOWN_STRATEGIES:
            raise ConfigError(
                f"C3_5RefinerConfig.strategy={self.strategy!r} not in "
                f"{sorted(KNOWN_STRATEGIES)}"
            )
        if self.residual_threshold_px <= 0.0:
            raise ConfigError(
                "C3_5RefinerConfig.residual_threshold_px must be > 0; "
                f"got {self.residual_threshold_px}"
            )
        if not (0.0 < self.invocation_rate_warn_threshold < 1.0):
            raise ConfigError(
                "C3_5RefinerConfig.invocation_rate_warn_threshold must be in "
                f"(0, 1); got {self.invocation_rate_warn_threshold}"
            )
