"""
Tests for advanced_search_system/constraints/constraint_analyzer.py

Tests cover:
- ConstraintAnalyzer initialization
- extract_constraints method
- _parse_constraint_type method
- _parse_weight method
"""

from unittest.mock import Mock


class TestConstraintAnalyzerInit:
    """Tests for ConstraintAnalyzer initialization."""

    def test_stores_model(self):
        """Test that model is stored."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        analyzer = ConstraintAnalyzer(mock_model)

        assert analyzer.model is mock_model


class TestParseConstraintType:
    """Tests for ConstraintAnalyzer._parse_constraint_type method."""

    def test_parses_property(self):
        """Test parsing property type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("property")

        assert result == ConstraintType.PROPERTY

    def test_parses_name_pattern(self):
        """Test parsing name_pattern type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("name_pattern")

        assert result == ConstraintType.NAME_PATTERN

    def test_parses_event(self):
        """Test parsing event type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("event")

        assert result == ConstraintType.EVENT

    def test_parses_statistic(self):
        """Test parsing statistic type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("statistic")

        assert result == ConstraintType.STATISTIC

    def test_parses_temporal(self):
        """Test parsing temporal type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("temporal")

        assert result == ConstraintType.TEMPORAL

    def test_parses_location(self):
        """Test parsing location type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("location")

        assert result == ConstraintType.LOCATION

    def test_parses_comparison(self):
        """Test parsing comparison type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("comparison")

        assert result == ConstraintType.COMPARISON

    def test_parses_existence(self):
        """Test parsing existence type."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("existence")

        assert result == ConstraintType.EXISTENCE

    def test_case_insensitive(self):
        """Test that parsing is case-insensitive."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        assert (
            analyzer._parse_constraint_type("PROPERTY")
            == ConstraintType.PROPERTY
        )
        assert (
            analyzer._parse_constraint_type("Property")
            == ConstraintType.PROPERTY
        )
        assert (
            analyzer._parse_constraint_type("TEMPORAL")
            == ConstraintType.TEMPORAL
        )

    def test_unknown_type_defaults_to_property(self):
        """Test that unknown type defaults to PROPERTY."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_constraint_type("unknown_type")

        assert result == ConstraintType.PROPERTY


class TestParseWeight:
    """Tests for ConstraintAnalyzer._parse_weight method."""

    def test_parses_int(self):
        """Test parsing integer weight."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight(1)

        assert result == 1.0

    def test_parses_float(self):
        """Test parsing float weight."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight(0.75)

        assert result == 0.75

    def test_parses_numeric_string(self):
        """Test parsing numeric string weight."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight("0.8")

        assert result == 0.8

    def test_parses_string_with_text_annotation(self):
        """Test parsing string with text annotation."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight("0.9 (high importance)")

        assert result == 0.9

    def test_extracts_first_number_from_string(self):
        """Test extracting first number from string."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight("Weight: 0.7 out of 1.0")

        assert result == 0.7

    def test_invalid_string_defaults_to_one(self):
        """Test that invalid string defaults to 1.0."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight("no numbers here")

        assert result == 1.0

    def test_empty_string_defaults_to_one(self):
        """Test that empty string defaults to 1.0."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        analyzer = ConstraintAnalyzer(Mock())

        result = analyzer._parse_weight("")

        assert result == 1.0


class TestExtractConstraints:
    """Tests for ConstraintAnalyzer.extract_constraints method."""

    def test_extracts_single_constraint(self):
        """Test extracting a single constraint."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: property
Description: The person is an actor
Value: must be an actor
Weight: 0.8
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Who is the actor?")

        assert len(constraints) == 1
        assert constraints[0].description == "The person is an actor"
        assert constraints[0].value == "must be an actor"
        assert constraints[0].weight == 0.8

    def test_extracts_multiple_constraints(self):
        """Test extracting multiple constraints."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: property
Description: First constraint
Value: first value
Weight: 0.9

CONSTRAINT_2:
Type: temporal
Description: Second constraint
Value: second value
Weight: 0.7
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test query")

        assert len(constraints) == 2
        assert constraints[0].description == "First constraint"
        assert constraints[1].description == "Second constraint"

    def test_generates_unique_ids(self):
        """Test that constraints get unique IDs."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: property
Description: First
Value: first
Weight: 1.0

CONSTRAINT_2:
Type: property
Description: Second
Value: second
Weight: 1.0
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert constraints[0].id == "c1"
        assert constraints[1].id == "c2"

    def test_handles_missing_weight(self):
        """Test handling constraint without weight."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: property
Description: No weight specified
Value: some value
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert len(constraints) == 1
        assert constraints[0].weight == 1.0  # Default

    def test_skips_incomplete_constraints(self):
        """Test that incomplete constraints are skipped."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: property
Description: Missing value

CONSTRAINT_2:
Type: property
Description: Complete constraint
Value: has value
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        # Only the complete constraint should be included
        assert len(constraints) == 1
        assert constraints[0].description == "Complete constraint"

    def test_handles_think_tags_in_response(self):
        """Test that think tags are removed from response."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""<think>Let me analyze this query...</think>
CONSTRAINT_1:
Type: property
Description: Test constraint
Value: test value
Weight: 0.5
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert len(constraints) == 1
        assert constraints[0].description == "Test constraint"

    def test_handles_empty_response(self):
        """Test handling empty model response."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="")

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert constraints == []

    def test_parses_constraint_type_correctly(self):
        """Test that constraint types are parsed correctly."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )
        from local_deep_research.advanced_search_system.constraints.base_constraint import (
            ConstraintType,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: temporal
Description: Time constraint
Value: in 2024
Weight: 0.8
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert constraints[0].type == ConstraintType.TEMPORAL

    def test_handles_extra_whitespace(self):
        """Test handling of extra whitespace in response."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type:   property
Description:   Test with spaces
Value:   value with spaces
Weight:   0.7
"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert len(constraints) == 1
        assert constraints[0].description == "Test with spaces"

    def test_processes_last_constraint(self):
        """Test that the last constraint is processed (not forgotten)."""
        from local_deep_research.advanced_search_system.constraints.constraint_analyzer import (
            ConstraintAnalyzer,
        )

        mock_model = Mock()
        # No trailing CONSTRAINT_ marker, so last one must be processed
        mock_model.invoke.return_value = Mock(
            content="""
CONSTRAINT_1:
Type: property
Description: First constraint
Value: first

CONSTRAINT_2:
Type: property
Description: Last constraint
Value: last"""
        )

        analyzer = ConstraintAnalyzer(mock_model)
        constraints = analyzer.extract_constraints("Test")

        assert len(constraints) == 2
        assert constraints[1].description == "Last constraint"
