"""Build A Phase 5: verify single-registry invariant after consolidation.

Ensures that recoil/api/sanctioned_fallbacks.py (FallbackEntry, api-side registry)
is gone and all its entries now live in the canonical
recoil/pipeline/_lib/sanctioned_fallbacks.py (FallbackRecord).
"""
from __future__ import annotations

import pytest

from recoil.pipeline._lib.sanctioned_fallbacks import (
    list_sanctioned_fallbacks,
    get_sanctioned_fallback,
)


class TestSingleRegistry:
    def test_api_module_is_gone(self):
        """recoil.api.sanctioned_fallbacks must not exist post-consolidation."""
        with pytest.raises(ImportError):
            import recoil.api.sanctioned_fallbacks  # noqa: F401

    def test_migrated_entries_present(self):
        """Entries that lived in the api-side registry are now in the canonical.

        Build A Phase 4 (2026-05-28): the 3 disguised-default fallbacks
        (episodes_synthesized_from_shot_index, scenes_synthesized_one_per_episode,
        episode_id_derived_from_filename_prefix) were retired. The remaining
        consolidated entries are pinned here.
        """
        names = {r.name for r in list_sanctioned_fallbacks()}
        # Surviving entries from the deleted api/sanctioned_fallbacks.py:
        assert "receipts_log_corrupt_line_skip" in names
        assert "shot_file_unreadable_drop" in names
        assert "take_id_not_on_disk" in names
        assert "proposal_id_not_pending" in names
        assert "workspace_state_user_chose_discard" in names
        assert "workspace_state_user_chose_report" in names
        assert "project_load_failure_isolated" in names
        assert "take_status_unsignaled_default_queued" in names
        assert "take_eval_state_unsignaled_default_pending" in names
        # Original Phase E.3 entries also present:
        assert "model_alias_resolver" in names
        assert "cache_miss_canonical_source" in names
        assert "cost_unknown_telemetry_zero" in names
        # Build A Phase 4: the 3 disguised-default fallbacks are GONE.
        assert "episodes_synthesized_from_shot_index" not in names
        assert "scenes_synthesized_one_per_episode" not in names
        assert "episode_id_derived_from_filename_prefix" not in names

    def test_quality_neutrality_argument_required(self):
        """All registered records must have a non-empty quality_neutrality_argument."""
        for record in list_sanctioned_fallbacks():
            assert record.quality_neutrality_argument, (
                f"{record.name}: quality_neutrality_argument is empty"
            )

    def test_expected_substitution_required(self):
        """All registered records must have a non-empty expected_substitution."""
        for record in list_sanctioned_fallbacks():
            assert record.expected_substitution, (
                f"{record.name}: expected_substitution is empty"
            )

    def test_all_names_unique(self):
        """No duplicate names in the registry."""
        names = [r.name for r in list_sanctioned_fallbacks()]
        assert len(names) == len(set(names)), (
            f"Duplicate names found: {[n for n in names if names.count(n) > 1]}"
        )

    def test_get_sanctioned_fallback_returns_record(self):
        """get_sanctioned_fallback returns the record for a known name."""
        record = get_sanctioned_fallback("receipts_log_corrupt_line_skip")
        assert record.name == "receipts_log_corrupt_line_skip"
        assert record.justification
        assert record.quality_neutrality_argument
        assert record.expected_substitution

    def test_get_sanctioned_fallback_raises_for_unknown(self):
        """get_sanctioned_fallback raises KeyError for an unknown name."""
        with pytest.raises(KeyError):
            get_sanctioned_fallback("bogus_name_that_never_existed")
