"""
Tests for the CollectionSearchEngine class.

Tests cover:
- Initialization and configuration
- Collection-specific embedding settings loading
- Search within a specific collection
- Document URL generation
- Class attributes
"""

from unittest.mock import Mock, patch


class TestCollectionSearchEngineInit:
    """Tests for CollectionSearchEngine initialization."""

    def test_init_with_collection_id(self):
        """Initialize with collection ID and name."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch.object(
                    CollectionSearchEngine,
                    "_load_collection_embedding_settings",
                ):
                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                    )

                    assert engine.collection_id == "abc123"
                    assert engine.collection_name == "Test Collection"
                    assert engine.collection_key == "collection_abc123"

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

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch.object(
                    CollectionSearchEngine,
                    "_load_collection_embedding_settings",
                ):
                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        max_results=25,
                    )

                    assert engine.max_results == 25

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

        mock_llm = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch.object(
                    CollectionSearchEngine,
                    "_load_collection_embedding_settings",
                ):
                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        llm=mock_llm,
                    )

                    assert engine.llm is mock_llm


class TestLoadCollectionEmbeddingSettings:
    """Tests for _load_collection_embedding_settings method."""

    def test_load_settings_without_username(self):
        """Load settings does nothing without username."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                engine = CollectionSearchEngine(
                    collection_id="abc123",
                    collection_name="Test Collection",
                )

                # Should not raise, just log warning
                assert engine.username is None

    def test_load_settings_with_rag_index(self):
        """Load settings from RAG index."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        mock_rag_index = Mock()
        mock_rag_index.embedding_model = "custom-model"
        mock_rag_index.embedding_model_type = Mock(value="ollama")
        mock_rag_index.chunk_size = 2000
        mock_rag_index.chunk_overlap = 400

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = mock_rag_index

                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        settings_snapshot=settings,
                    )

                    assert engine.embedding_model == "custom-model"
                    assert engine.embedding_provider == "ollama"
                    assert engine.chunk_size == 2000
                    assert engine.chunk_overlap == 400

    def test_load_settings_no_rag_index(self):
        """Load settings handles missing RAG index."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = None

                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        settings_snapshot=settings,
                    )

                    # Should not raise, just log warning
                    assert engine.collection_id == "abc123"

    def test_load_settings_exception(self):
        """Load settings handles exceptions gracefully."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session",
                    side_effect=Exception("Database error"),
                ):
                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        settings_snapshot=settings,
                    )

                    # Should not raise
                    assert engine.collection_id == "abc123"


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

    def test_search_without_username(self):
        """Search returns empty without username."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch.object(
                    CollectionSearchEngine,
                    "_load_collection_embedding_settings",
                ):
                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                    )
                    results = engine.search("test query")

                    assert results == []

    def test_search_no_rag_index(self):
        """Search returns empty when no RAG index."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = None

                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        settings_snapshot=settings,
                    )
                    results = engine.search("test query")

                    assert results == []

    def test_search_no_indexed_documents(self):
        """Search returns empty when no indexed documents."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        mock_rag_index = Mock()
        mock_rag_index.embedding_model = "all-MiniLM-L6-v2"
        mock_rag_index.embedding_model_type = Mock(
            value="sentence_transformers"
        )
        mock_rag_index.chunk_size = 1000
        mock_rag_index.chunk_overlap = 200

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = mock_rag_index

                    with patch(
                        "local_deep_research.web_search_engines.engines.search_engine_collection.LibraryRAGService"
                    ) as mock_rag_service:
                        # Set up mock RAG service instance for context manager
                        mock_rag_instance = Mock()
                        mock_rag_instance.get_rag_stats.return_value = {
                            "indexed_documents": 0
                        }
                        mock_rag_service.return_value.__enter__.return_value = (
                            mock_rag_instance
                        )
                        mock_rag_service.return_value.__exit__.return_value = (
                            None
                        )

                        engine = CollectionSearchEngine(
                            collection_id="abc123",
                            collection_name="Test Collection",
                            settings_snapshot=settings,
                        )
                        results = engine.search("test query")

                        assert results == []

    def test_search_returns_results(self):
        """Search returns formatted results."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        mock_rag_index = Mock()
        mock_rag_index.embedding_model = "all-MiniLM-L6-v2"
        mock_rag_index.embedding_model_type = Mock(
            value="sentence_transformers"
        )
        mock_rag_index.chunk_size = 1000
        mock_rag_index.chunk_overlap = 200

        mock_doc = Mock()
        mock_doc.page_content = "This is the document content for testing."
        mock_doc.metadata = {
            "source_id": "123",
            "document_title": "Test Document",
        }

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = mock_rag_index

                    with patch(
                        "local_deep_research.web_search_engines.engines.search_engine_collection.LibraryRAGService"
                    ) as mock_rag_service:
                        # Set up mock RAG service instance for context manager
                        mock_rag_instance = Mock()
                        mock_rag_instance.get_rag_stats.return_value = {
                            "indexed_documents": 1
                        }
                        mock_vector_store = Mock()
                        mock_vector_store.similarity_search_with_score.return_value = [
                            (mock_doc, 0.5)
                        ]
                        mock_rag_instance.load_or_create_faiss_index.return_value = mock_vector_store
                        mock_rag_service.return_value.__enter__.return_value = (
                            mock_rag_instance
                        )
                        mock_rag_service.return_value.__exit__.return_value = (
                            None
                        )

                        with patch.object(
                            CollectionSearchEngine,
                            "_get_document_url",
                            return_value="/library/document/123",
                        ):
                            engine = CollectionSearchEngine(
                                collection_id="abc123",
                                collection_name="Test Collection",
                                settings_snapshot=settings,
                            )
                            results = engine.search("test query")

                            assert len(results) == 1
                            assert results[0]["title"] == "Test Document"
                            assert results[0]["source"] == "library"
                            assert results[0]["source_type"] == "library"
                            assert results[0]["url"] == "/library/document/123"

    def test_search_empty_vector_results(self):
        """Search handles empty vector search results."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        mock_rag_index = Mock()
        mock_rag_index.embedding_model = "all-MiniLM-L6-v2"
        mock_rag_index.embedding_model_type = Mock(
            value="sentence_transformers"
        )
        mock_rag_index.chunk_size = 1000
        mock_rag_index.chunk_overlap = 200

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = mock_rag_index

                    with patch(
                        "local_deep_research.web_search_engines.engines.search_engine_collection.LibraryRAGService"
                    ) as mock_rag_service:
                        # Set up mock RAG service instance for context manager
                        mock_rag_instance = Mock()
                        mock_rag_instance.get_rag_stats.return_value = {
                            "indexed_documents": 1
                        }
                        mock_vector_store = Mock()
                        mock_vector_store.similarity_search_with_score.return_value = []
                        mock_rag_instance.load_or_create_faiss_index.return_value = mock_vector_store
                        mock_rag_service.return_value.__enter__.return_value = (
                            mock_rag_instance
                        )
                        mock_rag_service.return_value.__exit__.return_value = (
                            None
                        )

                        engine = CollectionSearchEngine(
                            collection_id="abc123",
                            collection_name="Test Collection",
                            settings_snapshot=settings,
                        )
                        results = engine.search("test query")

                        assert results == []

    def test_search_exception(self):
        """Search re-raises so failures are not mistaken for no results."""
        import pytest

        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        mock_rag_index = Mock()
        mock_rag_index.embedding_model = "all-MiniLM-L6-v2"
        mock_rag_index.embedding_model_type = Mock(
            value="sentence_transformers"
        )
        mock_rag_index.chunk_size = 1000
        mock_rag_index.chunk_overlap = 200

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = mock_rag_index

                    with patch(
                        "local_deep_research.web_search_engines.engines.search_engine_collection.LibraryRAGService",
                        side_effect=Exception("RAG service error"),
                    ):
                        engine = CollectionSearchEngine(
                            collection_id="abc123",
                            collection_name="Test Collection",
                            settings_snapshot=settings,
                        )
                        with pytest.raises(
                            Exception, match="RAG service error"
                        ):
                            engine.search("test query")


class TestGetDocumentUrl:
    """Tests for _get_document_url method."""

    def test_get_document_url_no_doc_id(self):
        """Get document URL returns # for no doc ID."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch.object(
                    CollectionSearchEngine,
                    "_load_collection_embedding_settings",
                ):
                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                    )
                    url = engine._get_document_url(None)

                    assert url == "#"

    def test_get_document_url_default(self):
        """Get document URL returns default library URL."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    # Mock no document found
                    mock_session.return_value.__enter__.return_value.query.return_value.filter_by.return_value.first.return_value = None

                    engine = CollectionSearchEngine(
                        collection_id="abc123",
                        collection_name="Test Collection",
                        settings_snapshot=settings,
                    )
                    url = engine._get_document_url("doc123")

                    assert url == "/library/document/doc123"

    def test_get_document_url_with_pdf(self):
        """Get document URL returns PDF URL when PDF exists."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        settings = {"_username": "testuser"}

        mock_document = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_library.get_setting_from_snapshot",
            return_value=None,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.search_engine_library.get_server_url",
                return_value="http://localhost:5000",
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.search_engine_collection.get_user_db_session"
                ) as mock_session:
                    # First call during init returns None for RAG index
                    # Subsequent calls for document lookup return the document
                    mock_query = Mock()
                    mock_query.filter_by.return_value.first.side_effect = [
                        None,  # RAG index query
                        mock_document,  # Document query
                    ]
                    mock_session.return_value.__enter__.return_value.query.return_value = mock_query

                    with patch(
                        "local_deep_research.web_search_engines.engines.search_engine_collection.get_setting_from_snapshot",
                        return_value="/path/to/library",
                    ):
                        with patch(
                            "local_deep_research.web_search_engines.engines.search_engine_collection.get_library_directory",
                            return_value="/default/library",
                        ):
                            with patch(
                                "local_deep_research.web_search_engines.engines.search_engine_collection.PDFStorageManager"
                            ) as mock_pdf_manager:
                                mock_pdf_manager.return_value.has_pdf.return_value = True

                                engine = CollectionSearchEngine(
                                    collection_id="abc123",
                                    collection_name="Test Collection",
                                    settings_snapshot=settings,
                                )
                                url = engine._get_document_url("doc123")

                                assert url == "/library/document/doc123/pdf"


class TestClassAttributes:
    """Tests for class attributes."""

    def test_is_local(self):
        """CollectionSearchEngine is marked as local."""
        from local_deep_research.web_search_engines.engines.search_engine_collection import (
            CollectionSearchEngine,
        )

        assert CollectionSearchEngine.is_local is True
