"""
Tests for the LocalAllSearchEngine class.

Tests cover:
- Initialization and configuration
- Local engine discovery
- Search across all collections
- Preview aggregation
- Full content retrieval
"""

from unittest.mock import Mock, patch


class TestLocalAllSearchEngineInit:
    """Tests for LocalAllSearchEngine initialization."""

    def test_init_with_defaults(self):
        """Initialize with default values."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine()

            assert engine.max_results == 10
            assert engine.local_engines == {}

    def test_init_with_custom_max_results(self):
        """Initialize with custom max_results."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine(max_results=25)

            assert engine.max_results == 25

    def test_init_discovers_local_engines(self):
        """Initialize and discover local collection engines."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine = Mock()
        mock_engine.name = "Test Collection"
        mock_engine.description = "Test description"

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["collection1", "collection2"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                return_value=mock_engine,
            ):
                engine = LocalAllSearchEngine()

                assert "collection1" in engine.local_engines
                assert "collection2" in engine.local_engines

    def test_init_handles_engine_creation_failure(self):
        """Initialize handles engine creation failure gracefully."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["collection1"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                side_effect=Exception("Engine creation failed"),
            ):
                engine = LocalAllSearchEngine()

                assert engine.local_engines == {}

    def test_init_handles_import_error(self):
        """Initialize handles ImportError for local_search_engines."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            side_effect=ImportError("No config found"),
        ):
            engine = LocalAllSearchEngine()

            assert engine.local_engines == {}

    def test_init_with_llm(self):
        """Initialize with LLM."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_llm = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine(llm=mock_llm)

            assert engine.llm is mock_llm

    def test_init_with_settings_snapshot(self):
        """Initialize with settings snapshot."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        settings = {"_username": "testuser"}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine(settings_snapshot=settings)

            assert engine.settings_snapshot == settings

    def test_init_with_programmatic_mode(self):
        """Initialize with programmatic mode."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine(programmatic_mode=True)

            assert engine.programmatic_mode is True


class TestGetPreviews:
    """Tests for _get_previews method."""

    def test_get_previews_returns_aggregated_results(self):
        """Get previews returns results from all local engines."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine1 = Mock()
        mock_engine1.name = "Collection 1"
        mock_engine1.description = "Description 1"
        mock_engine1._get_previews.return_value = [
            {"id": "1", "snippet": "Result 1", "similarity": 0.9}
        ]

        mock_engine2 = Mock()
        mock_engine2.name = "Collection 2"
        mock_engine2.description = "Description 2"
        mock_engine2._get_previews.return_value = [
            {"id": "2", "snippet": "Result 2", "similarity": 0.8}
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1", "col2"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine"
            ) as mock_create:
                mock_create.side_effect = [mock_engine1, mock_engine2]

                engine = LocalAllSearchEngine()
                previews = engine._get_previews("test query")

                assert len(previews) == 2
                assert previews[0]["collection_id"] == "col1"
                assert previews[1]["collection_id"] == "col2"

    def test_get_previews_sorts_by_similarity(self):
        """Get previews sorts results by similarity."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine1 = Mock()
        mock_engine1.name = "Collection 1"
        mock_engine1.description = "Description 1"
        mock_engine1._get_previews.return_value = [
            {"id": "1", "snippet": "Result 1", "similarity": 0.5}
        ]

        mock_engine2 = Mock()
        mock_engine2.name = "Collection 2"
        mock_engine2.description = "Description 2"
        mock_engine2._get_previews.return_value = [
            {"id": "2", "snippet": "Result 2", "similarity": 0.9}
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1", "col2"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine"
            ) as mock_create:
                mock_create.side_effect = [mock_engine1, mock_engine2]

                engine = LocalAllSearchEngine()
                previews = engine._get_previews("test query")

                # Higher similarity should come first
                assert previews[0]["similarity"] == 0.9
                assert previews[1]["similarity"] == 0.5

    def test_get_previews_limits_results(self):
        """Get previews limits results to max_results."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine = Mock()
        mock_engine.name = "Collection"
        mock_engine.description = "Description"
        mock_engine._get_previews.return_value = [
            {
                "id": str(i),
                "snippet": f"Result {i}",
                "similarity": 0.9 - i * 0.1,
            }
            for i in range(10)
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                return_value=mock_engine,
            ):
                engine = LocalAllSearchEngine(max_results=5)
                previews = engine._get_previews("test query")

                assert len(previews) == 5

    def test_get_previews_empty_results(self):
        """Get previews handles no local engines."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine()
            previews = engine._get_previews("test query")

            assert previews == []

    def test_get_previews_handles_engine_error(self):
        """Get previews handles engine search error gracefully."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine = Mock()
        mock_engine.name = "Collection"
        mock_engine.description = "Description"
        mock_engine._get_previews.side_effect = Exception("Search error")

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                return_value=mock_engine,
            ):
                engine = LocalAllSearchEngine()
                previews = engine._get_previews("test query")

                assert previews == []

    def test_get_previews_adds_collection_info(self):
        """Get previews adds collection info to each preview."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine = Mock()
        mock_engine.name = "My Collection"
        mock_engine.description = "Collection description"
        mock_engine._get_previews.return_value = [
            {"id": "1", "snippet": "Result"}
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["my_collection"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                return_value=mock_engine,
            ):
                engine = LocalAllSearchEngine()
                previews = engine._get_previews("test query")

                assert previews[0]["collection_id"] == "my_collection"
                assert previews[0]["collection_name"] == "My Collection"
                assert (
                    previews[0]["collection_description"]
                    == "Collection description"
                )


class TestGetFullContent:
    """Tests for _get_full_content method."""

    def test_get_full_content_delegates_to_engines(self):
        """Get full content delegates to appropriate collection engines."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine = Mock()
        mock_engine.name = "Collection"
        mock_engine.description = "Description"
        mock_engine._get_full_content.return_value = [
            {"id": "1", "full_content": "Full content 1"}
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                return_value=mock_engine,
            ):
                engine = LocalAllSearchEngine()

                items = [{"id": "1", "collection_id": "col1"}]
                results = engine._get_full_content(items)

                assert len(results) == 1
                assert results[0]["full_content"] == "Full content 1"

    def test_get_full_content_groups_by_collection(self):
        """Get full content groups items by collection."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine1 = Mock()
        mock_engine1.name = "Collection 1"
        mock_engine1.description = "Description 1"
        mock_engine1._get_full_content.return_value = [
            {"id": "1", "full_content": "Content 1"}
        ]

        mock_engine2 = Mock()
        mock_engine2.name = "Collection 2"
        mock_engine2.description = "Description 2"
        mock_engine2._get_full_content.return_value = [
            {"id": "2", "full_content": "Content 2"}
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1", "col2"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine"
            ) as mock_create:
                mock_create.side_effect = [mock_engine1, mock_engine2]

                engine = LocalAllSearchEngine()

                items = [
                    {"id": "1", "collection_id": "col1"},
                    {"id": "2", "collection_id": "col2"},
                ]
                results = engine._get_full_content(items)

                assert len(results) == 2

    def test_get_full_content_handles_engine_error(self):
        """Get full content handles engine error gracefully."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        mock_engine = Mock()
        mock_engine.name = "Collection"
        mock_engine.description = "Description"
        mock_engine._get_full_content.side_effect = Exception("Content error")

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=["col1"],
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_local_all.create_search_engine",
                return_value=mock_engine,
            ):
                engine = LocalAllSearchEngine()

                items = [
                    {"id": "1", "collection_id": "col1", "snippet": "Preview"}
                ]
                results = engine._get_full_content(items)

                # Should return original items on error
                assert len(results) == 1
                assert results[0]["id"] == "1"

    def test_get_full_content_handles_unknown_collection(self):
        """Get full content handles items with unknown collection."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine()

            items = [{"id": "1", "collection_id": "unknown_collection"}]
            results = engine._get_full_content(items)

            # Should return the unprocessed item
            assert len(results) == 1
            assert results[0]["id"] == "1"

    def test_get_full_content_handles_missing_collection_id(self):
        """Get full content handles items without collection_id."""
        from local_deep_research.web_search_engines.engines.search_engine_local_all import (
            LocalAllSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_local_all.local_search_engines",
            return_value=[],
        ):
            engine = LocalAllSearchEngine()

            items = [{"id": "1", "snippet": "No collection ID"}]
            results = engine._get_full_content(items)

            # Should return unprocessed item
            assert len(results) == 1
            assert results[0]["id"] == "1"
