"""
Tests for the Handle Test Registry: Self-Referential Test Data.

These tests verify that test data can be stored as MCards and
retrieved via handles, then used to execute the actual versioning tests.
"""

from pathlib import Path

import pytest
import yaml

from chapters.chapter_02_handle.handle_test_registry import (
    HandleTestRegistry,
    load_test_registry,
    run_tests_from_handles,
    run_versioning_test_from_handle,
)


class TestHandleTestRegistry:
    """Tests for the HandleTestRegistry class."""

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

    def test_load_test_data_file(self, test_data_dir):
        """Test loading a single test data file and registering a handle."""
        registry = HandleTestRegistry()

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

        assert result["hash"] is not None
        assert result["handle"] == "single_update"
        assert result["parsed"]["name"] == "single_update"
        assert len(result["parsed"]["versions"]) == 2

    def test_get_test_data_by_handle(self, test_data_dir):
        """Test retrieving test data by handle."""
        registry = HandleTestRegistry()
        registry.load_test_data_file(
            test_data_dir / "multiple_updates.yaml", "multiple_updates"
        )

        data = registry.get_test_data("multiple_updates")

        assert data is not None
        assert data["parsed"]["name"] == "multiple_updates"
        assert data["parsed"]["expected_history_length"] == 2

    def test_load_all_test_data(self, test_data_dir):
        """Test loading all test data files from directory."""
        registry = load_test_registry(test_data_dir)

        handles = registry.list_registered_handles()

        assert len(handles) == 3
        assert "single_update" in handles
        assert "multiple_updates" in handles
        assert "content_lineage" in handles


class TestSelfReferentialTests:
    """Tests that use handles to retrieve and execute test cases."""

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

    def test_run_tests_from_handles(self, test_data_dir):
        """Test running all tests by retrieving test data from handles."""
        result = run_tests_from_handles({"test_data_dir": str(test_data_dir)})

        assert result["success"] is True
        assert len(result["results"]) == 3
        assert result["registry_info"]["total_loaded"] == 3

        for r in result["results"]:
            assert r["retrieved"] is True
            assert r["hash"] is not None

    def test_run_single_update_from_handle(self, test_data_dir):
        """Execute the 'single_update' test by retrieving it from a handle."""
        result = run_versioning_test_from_handle(
            {"test_data_dir": str(test_data_dir), "handle": "single_update"}
        )

        assert result["success"] is True
        assert result["test_name"] == "single_update"
        assert result["actual_history_length"] == 1
        assert result["expected_history_length"] == 1
        assert result["source_handle"] == "single_update"

    def test_run_multiple_updates_from_handle(self, test_data_dir):
        """Execute the 'multiple_updates' test by retrieving it from a handle."""
        result = run_versioning_test_from_handle(
            {"test_data_dir": str(test_data_dir), "handle": "multiple_updates"}
        )

        assert result["success"] is True
        assert result["test_name"] == "multiple_updates"
        assert result["actual_history_length"] == 2
        assert result["expected_history_length"] == 2

    def test_run_content_lineage_from_handle(self, test_data_dir):
        """Execute the 'content_lineage' test by retrieving it from a handle."""
        result = run_versioning_test_from_handle(
            {"test_data_dir": str(test_data_dir), "handle": "content_lineage"}
        )

        assert result["success"] is True
        assert result["test_name"] == "content_lineage"
        assert result["actual_history_length"] == 3
        assert result["expected_history_length"] == 3
        assert "# Spec v1.0" in result["final_content"]


class TestMetaTestIntegration:
    """Integration tests that load the CLM and execute its meta-examples."""

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

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

    def test_clm_meta_examples(self, clm_file, test_data_dir):
        """Load the CLM and verify all meta-examples can be retrieved."""
        with open(clm_file) as f:
            clm_spec = yaml.safe_load(f)

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

        registry = load_test_registry(test_data_dir)

        for example in meta_examples:
            handle = example["handle"]
            expected_fields = example["expected_fields"]

            data = registry.get_test_data(handle)
            assert data is not None, f"Handle '{handle}' not found"

            parsed = data["parsed"]
            for field in expected_fields:
                assert (
                    field in parsed
                ), f"Field '{field}' not in test data for handle '{handle}'"

    def test_clm_test_data_sources(self, clm_file, test_data_dir):
        """Verify all test data sources defined in CLM exist and can be loaded."""
        with open(clm_file) as f:
            clm_spec = yaml.safe_load(f)

        sources = clm_spec.get("test_data_registry", {}).get("sources", [])

        registry = HandleTestRegistry()

        for source in sources:
            file_path = test_data_dir.parent / source["file"]
            handle = source["handle"]

            assert file_path.exists(), f"Source file '{file_path}' does not exist"

            result = registry.load_test_data_file(file_path, handle)
            assert result["hash"] is not None
            assert result["handle"] == handle
