"""C3 ``CrossDomainMatcher`` config block (AZ-344).

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

``strategy`` selects one of the three concrete backbones
(``disk_lightglue``, ``aliked_lightglue``, ``xfeat``); the
composition-root factory respects compile-time
``BUILD_MATCHER_<variant>`` gating on top of this label.

``min_inliers_threshold`` is the per-candidate floor: candidates
whose RANSAC inlier count falls below this value are treated as
failed (drop-and-continue) and counted into
``MatcherHealth.consecutive_low_inlier``. Default 60 — leaves
headroom below the AC-1.1 floor (p5 ≥ 80) so calibration drift
does not immediately trip the spoof gate; FT-P-19 telemetry will
tune it.

``residual_warn_threshold_px`` is the median reprojection-residual
limit (pixels) above which the matcher emits a WARN log; default
2.5 px (the AC-1.2 floor).
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Final

from gps_denied_onboard.config.schema import ConfigError

__all__ = [
    "C3MatcherConfig",
    "KNOWN_STRATEGIES",
]


KNOWN_STRATEGIES: Final[frozenset[str]] = frozenset(
    {"disk_lightglue", "aliked_lightglue", "xfeat"}
)


@dataclass(frozen=True)
class C3MatcherConfig:
    """Per-component config for C3 cross-domain matcher."""

    strategy: str = "disk_lightglue"
    min_inliers_threshold: int = 60
    residual_warn_threshold_px: float = 2.5

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