"""
Tests for normalize_entity_query utility function.

This function normalizes entity + constraint combinations for consistent
caching, using LRU cache for performance. It was previously untested.

Covers:
- Basic normalization (lowercase, whitespace)
- Quote stripping behavior (via .split())
- Empty/whitespace inputs
- Unicode handling
- LRU cache behavior (same input → same output)
"""


def _get_fn():
    """Import and return normalize_entity_query, clearing its LRU cache."""
    from local_deep_research.utilities.search_cache import (
        normalize_entity_query,
    )

    normalize_entity_query.cache_clear()
    return normalize_entity_query


class TestNormalizeEntityQueryBasics:
    """Basic normalization tests."""

    def test_lowercases_entity(self):
        """Entity is lowercased."""
        fn = _get_fn()
        result = fn("John Smith", "born")
        assert "john smith" in result

    def test_lowercases_constraint(self):
        """Constraint is lowercased."""
        fn = _get_fn()
        result = fn("python", "RELEASE DATE")
        assert "release date" in result

    def test_combines_entity_and_constraint(self):
        """Result is 'entity constraint' with a space separator."""
        fn = _get_fn()
        result = fn("python", "release date")
        assert result == "python release date"

    def test_strips_leading_trailing_whitespace(self):
        """Leading/trailing whitespace is removed."""
        fn = _get_fn()
        result = fn("  python  ", "  release date  ")
        assert result == "python release date"

    def test_collapses_internal_whitespace(self):
        """Multiple internal spaces collapsed to single space."""
        fn = _get_fn()
        result = fn("John    Michael   Smith", "birth   date")
        assert result == "john michael smith birth date"

    def test_tabs_and_newlines_normalized(self):
        """Tabs and newlines treated as whitespace and collapsed."""
        fn = _get_fn()
        result = fn("John\tSmith", "born\nin")
        assert result == "john smith born in"


class TestNormalizeEntityQueryEdgeCases:
    """Edge cases and unusual inputs."""

    def test_empty_entity(self):
        """Empty entity produces just the constraint."""
        fn = _get_fn()
        result = fn("", "born")
        assert result == " born"

    def test_empty_constraint(self):
        """Empty constraint produces just the entity."""
        fn = _get_fn()
        result = fn("python", "")
        assert result == "python "

    def test_both_empty(self):
        """Both empty produces a single space."""
        fn = _get_fn()
        result = fn("", "")
        assert result == " "

    def test_whitespace_only_entity(self):
        """Whitespace-only entity is stripped to empty."""
        fn = _get_fn()
        result = fn("   ", "born")
        assert result == " born"

    def test_unicode_characters(self):
        """Unicode characters are preserved and lowercased."""
        fn = _get_fn()
        result = fn("Ünîcödé", "Tëst")
        assert result == "ünîcödé tëst"

    def test_special_characters_preserved(self):
        """Special characters like hyphens and dots are preserved."""
        fn = _get_fn()
        result = fn("Marie-Curie", "birth.date")
        assert result == "marie-curie birth.date"

    def test_numbers_preserved(self):
        """Numbers in entity/constraint are preserved."""
        fn = _get_fn()
        result = fn("Python 3.12", "release 2024")
        assert result == "python 3.12 release 2024"


class TestNormalizeEntityQueryDeterminism:
    """Tests that normalization is deterministic and consistent."""

    def test_same_input_same_output(self):
        """Same inputs always produce the same result."""
        fn = _get_fn()
        r1 = fn("Test Entity", "test constraint")
        r2 = fn("Test Entity", "test constraint")
        assert r1 == r2

    def test_case_variations_produce_same_result(self):
        """Different cases of the same entity produce identical results."""
        fn = _get_fn()
        r1 = fn("John Smith", "born")
        r2 = fn("JOHN SMITH", "BORN")
        r3 = fn("john smith", "born")
        assert r1 == r2 == r3

    def test_whitespace_variations_produce_same_result(self):
        """Different whitespace of the same entity produce identical results."""
        fn = _get_fn()
        r1 = fn("John Smith", "born")
        r2 = fn("  John   Smith  ", "  born  ")
        assert r1 == r2


class TestNormalizeEntityQueryCache:
    """Tests for LRU cache behavior."""

    def test_cache_info_starts_empty(self):
        """After cache_clear, cache starts with zero hits/misses."""
        fn = _get_fn()
        info = fn.cache_info()
        assert info.hits == 0
        assert info.misses == 0

    def test_cache_hit_on_repeat_call(self):
        """Second call with same args is a cache hit."""
        fn = _get_fn()
        fn("test", "query")
        fn("test", "query")
        info = fn.cache_info()
        assert info.hits == 1
        assert info.misses == 1

    def test_different_args_are_cache_misses(self):
        """Different arguments are separate cache entries."""
        fn = _get_fn()
        fn("entity1", "constraint1")
        fn("entity2", "constraint2")
        info = fn.cache_info()
        assert info.misses == 2
        assert info.hits == 0

    def test_cache_maxsize_is_100(self):
        """LRU cache has maxsize of 100."""
        fn = _get_fn()
        info = fn.cache_info()
        assert info.maxsize == 100
