"""
High-value pure logic tests for base_constraint module.

Tests ConstraintType enum values and Constraint dataclass behavior
including defaults, post_init, to_search_terms, and is_critical.
"""

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


# ---------------------------------------------------------------------------
# ConstraintType enum tests
# ---------------------------------------------------------------------------


class TestConstraintTypeEnum:
    """Tests for ConstraintType enum values and lookup."""

    def test_property_value(self):
        assert ConstraintType.PROPERTY.value == "property"

    def test_name_pattern_value(self):
        assert ConstraintType.NAME_PATTERN.value == "name_pattern"

    def test_event_value(self):
        assert ConstraintType.EVENT.value == "event"

    def test_statistic_value(self):
        assert ConstraintType.STATISTIC.value == "statistic"

    def test_temporal_value(self):
        assert ConstraintType.TEMPORAL.value == "temporal"

    def test_location_value(self):
        assert ConstraintType.LOCATION.value == "location"

    def test_comparison_value(self):
        assert ConstraintType.COMPARISON.value == "comparison"

    def test_existence_value(self):
        assert ConstraintType.EXISTENCE.value == "existence"

    def test_enum_has_exactly_eight_members(self):
        assert len(ConstraintType) == 8

    def test_lookup_by_name(self):
        assert ConstraintType["PROPERTY"] is ConstraintType.PROPERTY
        assert ConstraintType["NAME_PATTERN"] is ConstraintType.NAME_PATTERN

    def test_lookup_by_value(self):
        assert ConstraintType("property") is ConstraintType.PROPERTY
        assert ConstraintType("event") is ConstraintType.EVENT


# ---------------------------------------------------------------------------
# Constraint dataclass tests
# ---------------------------------------------------------------------------


class TestConstraintDefaults:
    """Tests for Constraint field defaults and __post_init__."""

    def test_required_fields(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="test",
            value="some value",
        )
        assert c.id == "c1"
        assert c.type == ConstraintType.PROPERTY
        assert c.description == "test"
        assert c.value == "some value"

    def test_default_weight(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="test",
            value="v",
        )
        assert c.weight == 1.0

    def test_none_metadata_becomes_empty_dict(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="test",
            value="v",
            metadata=None,
        )
        assert c.metadata == {}

    def test_default_metadata_none_becomes_empty_dict(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="test",
            value="v",
        )
        assert c.metadata == {}

    def test_explicit_metadata_preserved(self):
        meta = {"source": "user", "priority": 1}
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="test",
            value="v",
            metadata=meta,
        )
        assert c.metadata == {"source": "user", "priority": 1}


# ---------------------------------------------------------------------------
# to_search_terms tests
# ---------------------------------------------------------------------------


class TestToSearchTerms:
    """Tests for Constraint.to_search_terms() across constraint types."""

    def test_property_returns_value_directly(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="desc",
            value="formed during ice age",
        )
        assert c.to_search_terms() == "formed during ice age"

    def test_name_pattern_appends_name_trail_mountain(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.NAME_PATTERN,
            description="desc",
            value="contains body part",
        )
        assert c.to_search_terms() == "contains body part name trail mountain"

    def test_event_appends_accident_incident(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.EVENT,
            description="desc",
            value="fall between 2000-2021",
        )
        assert c.to_search_terms() == "fall between 2000-2021 accident incident"

    def test_statistic_appends_statistics_data(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.STATISTIC,
            description="desc",
            value="84.5x ratio",
        )
        assert c.to_search_terms() == "84.5x ratio statistics data"

    def test_temporal_uses_str_value(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.TEMPORAL,
            description="desc",
            value="in 2014",
        )
        assert c.to_search_terms() == "in 2014"

    def test_location_uses_str_value(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.LOCATION,
            description="desc",
            value="Colorado",
        )
        assert c.to_search_terms() == "Colorado"

    def test_comparison_uses_str_value(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.COMPARISON,
            description="desc",
            value="more than 100",
        )
        assert c.to_search_terms() == "more than 100"

    def test_existence_uses_str_value(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.EXISTENCE,
            description="desc",
            value="has a viewpoint",
        )
        assert c.to_search_terms() == "has a viewpoint"

    def test_numeric_value_converted_to_string(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.TEMPORAL,
            description="desc",
            value=2014,
        )
        assert c.to_search_terms() == "2014"


# ---------------------------------------------------------------------------
# is_critical tests
# ---------------------------------------------------------------------------


class TestIsCritical:
    """Tests for Constraint.is_critical() logic."""

    def test_name_pattern_always_critical_default_weight(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.NAME_PATTERN,
            description="desc",
            value="v",
        )
        assert c.is_critical() is True

    def test_name_pattern_critical_even_with_low_weight(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.NAME_PATTERN,
            description="desc",
            value="v",
            weight=0.1,
        )
        assert c.is_critical() is True

    def test_weight_above_threshold_is_critical(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="desc",
            value="v",
            weight=0.9,
        )
        assert c.is_critical() is True

    def test_weight_exactly_0_8_not_critical(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.PROPERTY,
            description="desc",
            value="v",
            weight=0.8,
        )
        assert c.is_critical() is False

    def test_weight_below_threshold_not_critical(self):
        c = Constraint(
            id="c1",
            type=ConstraintType.EVENT,
            description="desc",
            value="v",
            weight=0.5,
        )
        assert c.is_critical() is False
