"""
Pure-logic tests for ConstraintParallelStrategy._build_constraint_query.

Tests entity-type quoting, constraint-value quoting, search-terms
appending, and edge cases — no LLM or search calls.
"""

from unittest.mock import Mock

from local_deep_research.advanced_search_system.constraints.base_constraint import (
    Constraint,
    ConstraintType,
)
from local_deep_research.advanced_search_system.strategies.constraint_parallel_strategy import (
    ConstraintParallelStrategy,
)


def _make_strategy(entity_type="unknown entity"):
    """Build a minimal Mock with state attributes."""
    s = Mock(spec=[])
    s.state = Mock(spec=[])
    s.state.entity_type = entity_type
    return s


def _constraint(value, ctype=ConstraintType.PROPERTY):
    return Constraint(
        id="c1", type=ctype, description=value, value=value, weight=1.0
    )


# ---------------------------------------------------------------------------
# _build_constraint_query
# ---------------------------------------------------------------------------


class TestBuildConstraintQuery:
    """Verify query construction with quoting logic."""

    def test_unknown_entity_type_excluded(self):
        """Unknown entity type is not included in query."""
        s = _make_strategy("unknown entity")
        c = _constraint("tall")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert "unknown entity" not in result
        assert "tall" in result

    def test_none_entity_type_excluded(self):
        """None entity type is not included in query."""
        s = _make_strategy(None)
        c = _constraint("red")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert result.startswith("red")

    def test_empty_entity_type_excluded(self):
        """Empty entity type is not included."""
        s = _make_strategy("")
        c = _constraint("blue")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert result.startswith("blue")

    def test_single_word_entity_not_quoted(self):
        """Single-word entity type is not quoted."""
        s = _make_strategy("mountain")
        c = _constraint("tall")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert result.startswith("mountain")
        assert '"mountain"' not in result

    def test_multi_word_entity_quoted(self):
        """Multi-word entity type gets quoted."""
        s = _make_strategy("national park")
        c = _constraint("large")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert '"national park"' in result

    def test_already_quoted_entity_not_double_quoted(self):
        """Entity already in quotes is not double-quoted."""
        s = _make_strategy('"national park"')
        c = _constraint("large")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert '""national park""' not in result
        assert '"national park"' in result

    def test_single_word_value_not_quoted(self):
        """Single-word constraint value is not quoted."""
        s = _make_strategy("mountain")
        c = _constraint("tall")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert '"tall"' not in result

    def test_multi_word_value_quoted(self):
        """Multi-word constraint value gets quoted."""
        s = _make_strategy("mountain")
        c = _constraint("very tall peak")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert '"very tall peak"' in result

    def test_search_terms_appended_when_different(self):
        """Search terms from constraint are appended when they differ from value."""
        s = _make_strategy()
        c = _constraint("Mount Rainier", ConstraintType.NAME_PATTERN)
        # NAME_PATTERN.to_search_terms() produces a different string
        search_terms = c.to_search_terms()
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        if search_terms and search_terms != "Mount Rainier":
            assert search_terms in result

    def test_search_terms_not_duplicated_when_same(self):
        """Search terms equal to value are not appended twice."""
        s = _make_strategy()
        c = _constraint("simple")
        # For simple values, to_search_terms() often returns the value itself
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        # Should not have "simple" duplicated
        parts = result.strip().split()
        assert (
            parts.count("simple") <= 2
        )  # entity_type excluded, so at most 1 or 2

    def test_all_parts_joined_with_space(self):
        """All query parts are joined with spaces."""
        s = _make_strategy("river")
        c = _constraint("long")
        result = ConstraintParallelStrategy._build_constraint_query(s, c)
        assert "river" in result
        assert "long" in result
