"""
Tests for BrowseCompEntityStrategy.

Tests cover:
- Initialization and configuration
- Entity candidate management
- Entity knowledge graph
- Constraint checking integration
- Entity pattern matching
- Error handling
"""

from unittest.mock import Mock, patch
import pytest


class TestEntityCandidate:
    """Tests for EntityCandidate dataclass."""

    def test_create_entity_candidate(self):
        """Create entity candidate with required fields."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityCandidate,
        )

        candidate = EntityCandidate(
            name="Test Entity",
            entity_type="company",
        )

        assert candidate.name == "Test Entity"
        assert candidate.entity_type == "company"
        assert candidate.aliases == []
        assert candidate.properties == {}
        assert candidate.sources == []
        assert candidate.confidence == 0.0
        assert candidate.constraint_matches == {}

    def test_create_entity_candidate_with_all_fields(self):
        """Create entity candidate with all fields."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityCandidate,
        )

        candidate = EntityCandidate(
            name="Test Entity",
            entity_type="person",
            aliases=["Alias 1", "Alias 2"],
            properties={"key": "value"},
            sources=["http://source1.com"],
            confidence=0.85,
            constraint_matches={"c1": 0.9},
        )

        assert candidate.name == "Test Entity"
        assert len(candidate.aliases) == 2
        assert candidate.properties["key"] == "value"
        assert len(candidate.sources) == 1
        assert candidate.confidence == 0.85
        assert candidate.constraint_matches["c1"] == 0.9


class TestEntityKnowledgeGraph:
    """Tests for EntityKnowledgeGraph class."""

    def test_init(self):
        """Initialize knowledge graph."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityKnowledgeGraph,
        )

        graph = EntityKnowledgeGraph()

        assert graph.entities == {}
        assert len(graph.constraint_evidence) == 0
        assert graph.search_cache == {}

    def test_add_entity(self):
        """Add entity to knowledge graph."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityKnowledgeGraph,
            EntityCandidate,
        )

        graph = EntityKnowledgeGraph()
        entity = EntityCandidate(name="Test", entity_type="company")

        graph.add_entity(entity)

        assert "Test" in graph.entities
        assert graph.entities["Test"] is entity

    def test_add_entity_merges_duplicate(self):
        """Add entity merges duplicate entries."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityKnowledgeGraph,
            EntityCandidate,
        )

        graph = EntityKnowledgeGraph()

        entity1 = EntityCandidate(
            name="Test",
            entity_type="company",
            aliases=["Alias1"],
            sources=["http://source1.com"],
        )
        entity2 = EntityCandidate(
            name="Test",
            entity_type="company",
            aliases=["Alias2"],
            sources=["http://source2.com"],
        )

        graph.add_entity(entity1)
        graph.add_entity(entity2)

        # Should merge aliases and sources
        assert len(graph.entities) == 1
        merged = graph.entities["Test"]
        assert "Alias1" in merged.aliases
        assert "Alias2" in merged.aliases
        assert len(merged.sources) == 2

    def test_add_constraint_evidence(self):
        """Add constraint evidence to graph."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityKnowledgeGraph,
        )

        graph = EntityKnowledgeGraph()

        graph.add_constraint_evidence(
            "constraint1",
            "entity1",
            {"text": "Evidence text", "confidence": 0.8},
        )

        assert "constraint1" in graph.constraint_evidence
        assert "entity1" in graph.constraint_evidence["constraint1"]

    def test_get_entities_by_constraint(self):
        """Get entities that match a constraint."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityKnowledgeGraph,
            EntityCandidate,
        )

        graph = EntityKnowledgeGraph()

        entity1 = EntityCandidate(
            name="Entity1",
            entity_type="company",
            constraint_matches={"c1": 0.9},
        )
        entity2 = EntityCandidate(
            name="Entity2",
            entity_type="company",
            constraint_matches={"c1": 0.3},
        )

        graph.add_entity(entity1)
        graph.add_entity(entity2)

        matches = graph.get_entities_by_constraint("c1", min_confidence=0.5)

        assert len(matches) == 1
        assert matches[0].name == "Entity1"

    def test_get_entities_by_constraint_sorted(self):
        """Get entities sorted by confidence."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            EntityKnowledgeGraph,
            EntityCandidate,
        )

        graph = EntityKnowledgeGraph()

        entity1 = EntityCandidate(
            name="Low",
            entity_type="company",
            constraint_matches={"c1": 0.6},
        )
        entity2 = EntityCandidate(
            name="High",
            entity_type="company",
            constraint_matches={"c1": 0.9},
        )

        graph.add_entity(entity1)
        graph.add_entity(entity2)

        matches = graph.get_entities_by_constraint("c1", min_confidence=0.5)

        assert len(matches) == 2
        assert matches[0].name == "High"  # Higher confidence first


class TestBrowseCompEntityStrategyInit:
    """Tests for BrowseCompEntityStrategy initialization."""

    def test_init_with_required_params(self):
        """Initialize with required parameters."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert strategy.model is mock_model
        assert strategy.search_engine is mock_search

    def test_init_creates_knowledge_graph(self):
        """Initialize creates knowledge graph."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert strategy.knowledge_graph is not None

    def test_init_creates_components_with_model(self):
        """Initialize creates components when model provided."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert strategy.constraint_analyzer is not None
        assert strategy.question_generator is not None
        assert strategy.constraint_checker is not None

    def test_init_entity_patterns(self):
        """Initialize includes entity patterns."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert "company" in strategy.entity_patterns
        assert "person" in strategy.entity_patterns
        assert "event" in strategy.entity_patterns
        assert "location" in strategy.entity_patterns
        assert "product" in strategy.entity_patterns


class TestBrowseCompEntityStrategySearch:
    """Tests for search method."""

    @pytest.mark.asyncio
    async def test_search_returns_tuple(self):
        """Search method returns tuple of (str, dict)."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Test response")

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        # Mock constraint analyzer
        with patch.object(
            strategy.constraint_analyzer, "extract_constraints", return_value=[]
        ):
            with patch.object(
                strategy.question_generator,
                "generate_questions",
                return_value=[],
            ):
                result = await strategy.search("test query")

        assert isinstance(result, tuple)
        assert len(result) == 2

    @pytest.mark.asyncio
    async def test_search_calls_progress_callback(self):
        """Search calls progress callback."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_search.run.return_value = []
        mock_model = Mock()
        mock_model.invoke.return_value = Mock(content="Test")

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        callback = Mock()

        with patch.object(
            strategy.constraint_analyzer, "extract_constraints", return_value=[]
        ):
            with patch.object(
                strategy.question_generator,
                "generate_questions",
                return_value=[],
            ):
                await strategy.search("test query", progress_callback=callback)

        # Callback should be called at some point
        assert callback.call_count >= 0


class TestEntityPatternMatching:
    """Tests for entity pattern matching."""

    def test_company_patterns(self):
        """Company patterns include expected terms."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        company_patterns = strategy.entity_patterns["company"]

        assert "company" in company_patterns
        assert "corporation" in company_patterns
        assert "firm" in company_patterns

    def test_person_patterns(self):
        """Person patterns include expected terms."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        person_patterns = strategy.entity_patterns["person"]

        assert "person" in person_patterns
        assert "individual" in person_patterns

    def test_location_patterns(self):
        """Location patterns include expected terms."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        location_patterns = strategy.entity_patterns["location"]

        assert "place" in location_patterns
        assert "city" in location_patterns
        assert "country" in location_patterns


class TestComponentIntegration:
    """Tests for component integration."""

    def test_constraint_checker_integration(self):
        """Constraint checker uses correct settings."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        checker = strategy.constraint_checker

        # Should have lenient thresholds for entities
        assert checker.negative_threshold == 0.3
        assert checker.positive_threshold == 0.4

    def test_explorer_integration(self):
        """Explorer is created with search and model."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert strategy.explorer is not None


class TestEvidenceGathering:
    """Tests for evidence gathering methods."""

    def test_gather_entity_evidence_method_exists(self):
        """Gather entity evidence method exists."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert hasattr(strategy, "_gather_entity_evidence")
        assert callable(strategy._gather_entity_evidence)


class TestBaseStrategyInheritance:
    """Tests for base strategy inheritance."""

    def test_inherits_from_base_strategy(self):
        """Strategy inherits from BaseSearchStrategy."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )
        from local_deep_research.advanced_search_system.strategies.base_strategy import (
            BaseSearchStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
        )

        assert isinstance(strategy, BaseSearchStrategy)

    def test_has_all_links_of_system(self):
        """Strategy has all_links_of_system attribute."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()
        links = [{"url": "http://test.com"}]

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
            all_links_of_system=links,
        )

        assert strategy.all_links_of_system is links

    def test_has_settings_snapshot(self):
        """Strategy has settings_snapshot attribute."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()
        mock_model = Mock()
        settings = {"key": "value"}

        strategy = BrowseCompEntityStrategy(
            model=mock_model,
            search=mock_search,
            settings_snapshot=settings,
        )

        assert strategy.settings_snapshot is settings


class TestErrorHandling:
    """Tests for error handling."""

    def test_init_without_model_logs_warning(self):
        """Initialize without model logs warning."""
        from local_deep_research.advanced_search_system.strategies.browsecomp_entity_strategy import (
            BrowseCompEntityStrategy,
        )

        mock_search = Mock()

        # Should not raise, but may log warning
        strategy = BrowseCompEntityStrategy(
            model=None,
            search=mock_search,
        )

        assert strategy.model is None
