"""CP-9 Phase 3 — eval module re-export sanity.

Mirrors test_module_load_registration.py shape — verifies the public
surface promised in pipeline/core/eval.py is reachable via
``from pipeline.core import ...`` and that constants are correctly typed.
"""

import sys
import pathlib

sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent.parent.parent))
from recoil.core.paths import ensure_pipeline_importable  # noqa: E402

ensure_pipeline_importable()


def test_eval_public_surface_imports_from_pipeline_core() -> None:
    """All Phase 3 public names must be reachable through pipeline.core."""
    from recoil.pipeline.core import (
        EvalContext,
        EvalResult,
        EvalNode,
        PanelOfJudges,
        EvalRegistry,
        register_eval_node,
        get_eval_node,
        list_eval_nodes,
        is_eval_registered,
        attach_eval_hooks,
        SUPPORTED_AGGREGATIONS,
        OUTLIER_THRESHOLD,
    )
    # Sanity — names resolve to the expected categories.
    assert isinstance(EvalContext, type)
    assert isinstance(EvalResult, type)
    assert isinstance(PanelOfJudges, type)
    assert isinstance(EvalRegistry, type)
    # EvalNode is a Protocol; behaves like a class object.
    assert hasattr(EvalNode, "_is_protocol") or callable(EvalNode)
    assert callable(register_eval_node)
    assert callable(get_eval_node)
    assert callable(list_eval_nodes)
    assert callable(is_eval_registered)
    assert callable(attach_eval_hooks)
    assert isinstance(SUPPORTED_AGGREGATIONS, tuple)
    assert isinstance(OUTLIER_THRESHOLD, float)


def test_eval_modality_constants_imports_from_pipeline_core() -> None:
    from recoil.pipeline.core import (
        MODALITY_EVAL_IMAGE_V1,
        MODALITY_EVAL_VIDEO_V1,
        MODALITY_EVAL_AUDIO_V1,
    )
    assert MODALITY_EVAL_IMAGE_V1 == "eval_image_v1"
    assert MODALITY_EVAL_VIDEO_V1 == "eval_video_v1"
    assert MODALITY_EVAL_AUDIO_V1 == "eval_audio_v1"


def test_eval_registry_facade_class_methods_present() -> None:
    from recoil.pipeline.core import EvalRegistry
    for name in ("register", "get", "list", "is_registered"):
        assert hasattr(EvalRegistry, name), name


def test_eval_module_in_all() -> None:
    import recoil.pipeline.core as pc
    expected = {
        "EvalContext", "EvalResult", "EvalNode",
        "PanelOfJudges", "EvalRegistry",
        "register_eval_node", "get_eval_node",
        "list_eval_nodes", "is_eval_registered",
        "attach_eval_hooks",
        "SUPPORTED_AGGREGATIONS", "OUTLIER_THRESHOLD",
        "MODALITY_EVAL_IMAGE_V1", "MODALITY_EVAL_VIDEO_V1",
        "MODALITY_EVAL_AUDIO_V1",
    }
    missing = expected - set(pc.__all__)
    assert not missing, f"missing from __all__: {missing}"


def test_supported_aggregations_locked_set() -> None:
    from recoil.pipeline.core import SUPPORTED_AGGREGATIONS
    assert SUPPORTED_AGGREGATIONS == ("median", "mean")


def test_outlier_threshold_locked_value() -> None:
    from recoil.pipeline.core import OUTLIER_THRESHOLD
    assert OUTLIER_THRESHOLD == 0.3
