"""
Tests for search_system.py

Tests cover:
- AdvancedSearchSystem initialization
- Strategy selection
- Search execution
- Progress callbacks
"""

from unittest.mock import Mock, patch


class TestAdvancedSearchSystemInit:
    """Tests for AdvancedSearchSystem initialization."""

    def test_init_basic(self):
        """Test basic initialization."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(llm=mock_llm, search=mock_search)

                assert system.model == mock_llm
                assert system.search == mock_search
                assert system.max_iterations == 1  # default
                assert system.questions_per_iteration == 3  # default

    def test_init_with_custom_iterations(self):
        """Test initialization with custom iterations."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(
                    llm=mock_llm,
                    search=mock_search,
                    max_iterations=5,
                    questions_per_iteration=10,
                )

                assert system.max_iterations == 5
                assert system.questions_per_iteration == 10

    def test_init_iterations_from_settings_snapshot(self):
        """Test iterations are read from settings snapshot."""
        mock_llm = Mock()
        mock_search = Mock()
        settings = {
            "search.iterations": {"value": 7},
            "search.questions_per_iteration": 4,
        }

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(
                    llm=mock_llm, search=mock_search, settings_snapshot=settings
                )

                assert system.max_iterations == 7
                assert system.questions_per_iteration == 4

    def test_init_programmatic_mode(self):
        """Test programmatic mode initialization."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(
                    llm=mock_llm, search=mock_search, programmatic_mode=True
                )

                assert system.programmatic_mode is True


class TestStrategySelection:
    """Tests for strategy selection."""

    def test_default_strategy(self):
        """Test default strategy is source-based."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                AdvancedSearchSystem(llm=mock_llm, search=mock_search)

                mock_create.assert_called_once()
                call_kwargs = mock_create.call_args[1]
                assert call_kwargs["strategy_name"] == "source-based"

    def test_custom_strategy(self):
        """Test custom strategy selection."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                AdvancedSearchSystem(
                    llm=mock_llm, search=mock_search, strategy_name="evidence"
                )

                call_kwargs = mock_create.call_args[1]
                assert call_kwargs["strategy_name"] == "evidence"

    def test_contextual_followup_strategy(self):
        """Test contextual followup strategy uses delegate."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.search_system.EnhancedContextualFollowUpStrategy"
            ) as mock_followup:
                mock_followup_strategy = Mock()
                mock_followup.return_value = mock_followup_strategy

                with patch(
                    "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
                ) as mock_citation:
                    mock_citation.return_value = Mock(
                        _create_documents=Mock(), _format_sources=Mock()
                    )

                    from local_deep_research.search_system import (
                        AdvancedSearchSystem,
                    )

                    AdvancedSearchSystem(
                        llm=mock_llm,
                        search=mock_search,
                        strategy_name="enhanced-contextual-followup",
                    )

                    # Verify create_strategy was called for the delegate
                    mock_create.assert_called()


class TestProgressCallbacks:
    """Tests for progress callback handling."""

    def test_set_progress_callback(self):
        """Test setting progress callback."""
        mock_llm = Mock()
        mock_search = Mock()
        mock_callback = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(llm=mock_llm, search=mock_search)

                system.set_progress_callback(mock_callback)

                assert system.progress_callback == mock_callback
                mock_strategy.set_progress_callback.assert_called_with(
                    mock_callback
                )

    def test_progress_callback_called(self):
        """Test progress callback is called internally."""
        mock_llm = Mock()
        mock_search = Mock()
        mock_callback = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(llm=mock_llm, search=mock_search)
                system.progress_callback = mock_callback

                system._progress_callback("Test", 50, {})

                mock_callback.assert_called_once_with("Test", 50, {})


class TestAnalyzeTopic:
    """Tests for analyze_topic method."""

    def test_analyze_topic_basic(self):
        """Test basic topic analysis."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = ["Q1"]
            mock_strategy.all_links_of_system = [{"link": "url1"}]
            mock_strategy.analyze_topic.return_value = {
                "current_knowledge": "Result"
            }
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                with patch(
                    "local_deep_research.news.core.search_integration.NewsSearchCallback"
                ):
                    from local_deep_research.search_system import (
                        AdvancedSearchSystem,
                    )

                    system = AdvancedSearchSystem(
                        llm=mock_llm, search=mock_search
                    )

                    result = system.analyze_topic("test query")

                    assert "current_knowledge" in result
                    assert result["query"] == "test query"
                    assert "search_system" in result
                    mock_strategy.analyze_topic.assert_called_once_with(
                        "test query"
                    )

    def test_analyze_topic_generates_search_id(self):
        """Test search ID is generated if not provided."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_strategy.analyze_topic.return_value = {}
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                with patch(
                    "local_deep_research.news.core.search_integration.NewsSearchCallback"
                ):
                    from local_deep_research.search_system import (
                        AdvancedSearchSystem,
                    )

                    system = AdvancedSearchSystem(
                        llm=mock_llm, search=mock_search
                    )

                    # Should not raise
                    result = system.analyze_topic("test")
                    assert isinstance(result, dict)

    def test_analyze_topic_preserves_links(self):
        """Test that links are preserved correctly."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            # Create a separate list object
            mock_strategy.all_links_of_system = [
                {"link": "url1"},
                {"link": "url2"},
            ]
            mock_strategy.analyze_topic.return_value = {}
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                with patch(
                    "local_deep_research.news.core.search_integration.NewsSearchCallback"
                ):
                    from local_deep_research.search_system import (
                        AdvancedSearchSystem,
                    )

                    system = AdvancedSearchSystem(
                        llm=mock_llm, search=mock_search
                    )

                    result = system.analyze_topic("test")

                    assert "all_links_of_system" in result


class TestPerformSearch:
    """Tests for _perform_search method."""

    def test_perform_search_extracts_settings(self):
        """Test settings are extracted from snapshot."""
        mock_llm = Mock()
        mock_search = Mock()
        settings = {
            "llm.provider": {"value": "anthropic"},
            "llm.model": {"value": "claude-3"},
            "search.tool": {"value": "searxng"},
        }

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_strategy.analyze_topic.return_value = {}
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                with patch(
                    "local_deep_research.news.core.search_integration.NewsSearchCallback"
                ):
                    from local_deep_research.search_system import (
                        AdvancedSearchSystem,
                    )

                    system = AdvancedSearchSystem(
                        llm=mock_llm,
                        search=mock_search,
                        settings_snapshot=settings,
                    )
                    progress_calls = []
                    system.progress_callback = (
                        lambda m, p, md: progress_calls.append((m, p, md))
                    )

                    system._perform_search(
                        "test", "id123", True, False, "user1"
                    )

                    # Check progress was called with LLM info
                    assert any("anthropic" in str(c) for c in progress_calls)

    def test_perform_search_handles_news_callback_error(self):
        """Test news callback errors are handled gracefully."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_strategy.analyze_topic.return_value = {}
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                with patch(
                    "local_deep_research.news.core.search_integration.NewsSearchCallback"
                ) as mock_callback:
                    mock_callback.side_effect = Exception("Callback error")

                    from local_deep_research.search_system import (
                        AdvancedSearchSystem,
                    )

                    system = AdvancedSearchSystem(
                        llm=mock_llm, search=mock_search
                    )

                    # Should not raise despite callback error
                    result = system._perform_search(
                        "test", "id", True, False, "user"
                    )
                    assert isinstance(result, dict)


class TestResearchContext:
    """Tests for research context handling."""

    def test_research_context_stored(self):
        """Test research context is stored."""
        mock_llm = Mock()
        mock_search = Mock()
        context = {"topic": "AI", "depth": "deep"}

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(
                    llm=mock_llm, search=mock_search, research_context=context
                )

                assert system.research_context == context

    def test_research_id_stored(self):
        """Test research ID is stored."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(
                    llm=mock_llm, search=mock_search, research_id="research-123"
                )

                assert system.research_id == "research-123"

    def test_username_stored(self):
        """Test username is stored."""
        mock_llm = Mock()
        mock_search = Mock()

        with patch(
            "local_deep_research.search_system_factory.create_strategy"
        ) as mock_create:
            mock_strategy = Mock()
            mock_strategy.questions_by_iteration = []
            mock_strategy.all_links_of_system = []
            mock_create.return_value = mock_strategy

            with patch(
                "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler"
            ) as mock_citation:
                mock_citation.return_value = Mock(
                    _create_documents=Mock(), _format_sources=Mock()
                )

                from local_deep_research.search_system import (
                    AdvancedSearchSystem,
                )

                system = AdvancedSearchSystem(
                    llm=mock_llm, search=mock_search, username="testuser"
                )

                assert system.username == "testuser"
