"""
Tests for Dual Retrieval: Hash vs Handle.

Verifies that content can be retrieved by either hash or handle,
and demonstrates the duality between immutable and mutable addressing.
"""

from pathlib import Path

import pytest
import yaml

from chapters.chapter_02_handle.dual_retrieval import (
    DualRetrievalRegistry,
    demonstrate_version_duality,
    dual_retrieve,
    dual_retrieve_all,
)


class TestDualRetrievalRegistry:
    """Tests for the DualRetrievalRegistry class."""

    @pytest.fixture
    def test_data_dir(self):
        return (
            Path(__file__).parent.parent
            / "chapters"
            / "chapter_02_handle"
            / "test_data"
        )

    def test_load_and_register_records_hash(self, test_data_dir):
        """Loading a file should record both the handle and the hash."""
        registry = DualRetrievalRegistry()

        result = registry.load_and_register(
            test_data_dir / "single_update.yaml", "single_update"
        )

        assert result["hash"] is not None
        assert result["name"] == "single_update"

        # Hash should be recorded
        recorded_hash = registry.get_recorded_hash("single_update")
        assert recorded_hash == result["hash"]

    def test_get_by_hash(self, test_data_dir):
        """Retrieve by hash should return exact content."""
        registry = DualRetrievalRegistry()
        result = registry.load_and_register(
            test_data_dir / "single_update.yaml", "single_update"
        )

        by_hash = registry.get_by_hash(result["hash"])

        assert by_hash is not None
        assert by_hash["hash"] == result["hash"]
        assert by_hash["retrieval_method"] == "hash"

    def test_get_by_handle(self, test_data_dir):
        """Retrieve by handle should return current content."""
        registry = DualRetrievalRegistry()
        registry.load_and_register(
            test_data_dir / "multiple_updates.yaml", "multiple_updates"
        )

        by_handle = registry.get_by_handle("multiple_updates")

        assert by_handle is not None
        assert by_handle["retrieval_method"] == "handle"
        assert by_handle["parsed"]["name"] == "multiple_updates"

    def test_dual_retrieve_equivalence(self, test_data_dir):
        """Dual retrieval should show equivalence between hash and handle."""
        registry = DualRetrievalRegistry()
        registry.load_and_register(
            test_data_dir / "content_lineage.yaml", "content_lineage"
        )

        result = registry.dual_retrieve("content_lineage")

        assert result["success"] is True
        assert result["content_matches"] is True
        assert result["hash_matches"] is True
        assert result["equivalence_verified"] is True


class TestDualRetrievalCLM:
    """Tests for the CLM entry points."""

    @pytest.fixture
    def test_data_dir(self):
        return (
            Path(__file__).parent.parent
            / "chapters"
            / "chapter_02_handle"
            / "test_data"
        )

    def test_dual_retrieve_single(self, test_data_dir):
        """Test dual retrieval for a single test case."""
        result = dual_retrieve(
            {"test_data_dir": str(test_data_dir), "name": "single_update"}
        )

        assert result["success"] is True
        assert result["name"] == "single_update"
        assert result["equivalence_verified"] is True

    def test_dual_retrieve_all_entries(self, test_data_dir):
        """Test dual retrieval for all test cases."""
        result = dual_retrieve_all({"test_data_dir": str(test_data_dir)})

        assert result["success"] is True
        assert result["total_entries"] == 3
        assert result["all_equivalence_verified"] is True

        # Verify hash registry was populated
        assert len(result["hash_registry"]) == 3
        for entry in result["hash_registry"]:
            assert "name" in entry
            assert "hash" in entry
            assert len(entry["hash"]) == 64  # SHA-256 hex

    def test_version_duality_demonstration(self):
        """Test that version updates affect handle but not hash retrieval."""
        result = demonstrate_version_duality(
            {
                "handle": "my_versioned_doc",
                "initial_content": "Version A - Original",
                "updated_content": "Version B - Updated",
            }
        )

        assert result["success"] is True

        assertions = result["assertions"]
        assert assertions["hash_v1_still_returns_v1"] is True
        assert assertions["hash_v2_returns_v2"] is True
        assert assertions["handle_returns_latest"] is True
        assert assertions["v1_hash_differs_from_v2"] is True

        # Verify the actual retrieval results
        retrievals = result["retrieval_results"]
        assert retrievals["get_by_hash_v1"] == "Version A - Original"
        assert retrievals["get_by_hash_v2"] == "Version B - Updated"
        assert retrievals["get_by_handle"] == "Version B - Updated"


class TestCLMIntegration:
    """Integration tests loading the CLM spec."""

    @pytest.fixture
    def clm_file(self):
        return (
            Path(__file__).parent.parent
            / "chapters"
            / "chapter_02_handle"
            / "dual_retrieval.clm"
        )

    @pytest.fixture
    def test_data_dir(self):
        return (
            Path(__file__).parent.parent
            / "chapters"
            / "chapter_02_handle"
            / "test_data"
        )

    def test_clm_examples(self, clm_file, test_data_dir):
        """Verify all examples in the CLM can be executed."""
        with open(clm_file) as f:
            clm_spec = yaml.safe_load(f)

        examples = clm_spec.get("examples", [])

        # First 3 examples are dual retrieval tests
        for example in examples[:3]:
            handle = example["handle"]
            result = dual_retrieve(
                {"test_data_dir": str(test_data_dir), "name": handle}
            )

            assert result["success"] is True, f"Failed for handle '{handle}'"
            assert result["equivalence_verified"] is True

    def test_clm_version_update_example(self, clm_file):
        """Execute the version update duality example from CLM."""
        with open(clm_file) as f:
            clm_spec = yaml.safe_load(f)

        examples = clm_spec.get("examples", [])
        version_example = examples[-1]  # Last example is version update

        result = demonstrate_version_duality(
            {
                "handle": version_example["handle"],
                "initial_content": version_example["initial_content"],
                "updated_content": version_example["updated_content"],
            }
        )

        assert result["success"] is True
        assert result["assertions"]["hash_v1_still_returns_v1"] is True
        assert result["assertions"]["handle_returns_latest"] is True
