"""
Tests for the Wikipedia search engine.

Tests cover:
- Initialization and configuration
- Preview generation
- Full content retrieval
- Language setting
- Error handling
"""

from unittest.mock import Mock, patch


class TestWikipediaSearchEngine:
    """Tests for the WikipediaSearchEngine class."""

    def test_initialization(self):
        """Test WikipediaSearchEngine initializes with correct parameters."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_llm = Mock()

        with patch("wikipedia.set_lang") as mock_set_lang:
            engine = WikipediaSearchEngine(
                max_results=5,
                language="fr",
                include_content=True,
                sentences=3,
                llm=mock_llm,
            )

            assert engine.max_results == 5
            assert engine.include_content is True
            assert engine.sentences == 3
            mock_set_lang.assert_called_with("fr")

    def test_is_public_flag(self):
        """Verify WikipediaSearchEngine is marked as public."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        assert WikipediaSearchEngine.is_public is True

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_success(self, mock_summary, mock_search):
        """Test successful preview generation."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = [
            "Python (programming language)",
            "Python (snake)",
        ]
        mock_summary.side_effect = [
            "Python is a high-level programming language.",
            "Python is a genus of constricting snakes.",
        ]

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine(max_results=5)
            previews = engine._get_previews("Python")

        assert len(previews) == 2
        assert previews[0]["title"] == "Python (programming language)"
        assert "programming language" in previews[0]["snippet"]
        assert previews[0]["source"] == "Wikipedia"
        assert "wikipedia.org" in previews[0]["link"]

    @patch("wikipedia.search")
    def test_get_previews_empty_results(self, mock_search):
        """Test handling of empty search results."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = []

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("nonexistent query xyz")

        assert previews == []

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_disambiguation_handling(
        self, mock_summary, mock_search
    ):
        """Test handling of disambiguation errors."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = ["Mercury"]

        # First call raises disambiguation, second call succeeds
        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Mercury", ["Mercury (planet)", "Mercury (element)"]
        )
        mock_summary.side_effect = [
            disambiguation_error,
            "Mercury is the closest planet to the Sun.",
        ]

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("Mercury")

        # Should have handled disambiguation and used first option
        assert len(previews) == 1
        assert (
            "planet" in previews[0]["snippet"].lower()
            or "planet" in previews[0]["title"].lower()
        )

    @patch("wikipedia.page")
    def test_get_full_content(self, mock_page):
        """Test full content retrieval."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_page_obj = Mock()
        mock_page_obj.title = "Python (programming language)"
        mock_page_obj.url = (
            "https://en.wikipedia.org/wiki/Python_(programming_language)"
        )
        mock_page_obj.content = "Python is a high-level programming language..."
        mock_page_obj.categories = ["Programming languages"]
        mock_page_obj.references = ["https://python.org"]
        mock_page_obj.links = ["Guido van Rossum"]
        mock_page_obj.images = ["python_logo.png"]
        mock_page_obj.sections = ["History", "Features"]
        mock_page.return_value = mock_page_obj

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            relevant_items = [
                {
                    "id": "Python (programming language)",
                    "title": "Python (programming language)",
                    "snippet": "Python is...",
                }
            ]

            results = engine._get_full_content(relevant_items)

        assert len(results) == 1
        assert results[0]["content"] == mock_page_obj.content
        assert results[0]["categories"] == ["Programming languages"]
        assert "History" in results[0]["sections"]

    def test_set_language(self):
        """Test language setting."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        with patch("wikipedia.set_lang") as mock_set_lang:
            engine = WikipediaSearchEngine(language="en")
            engine.set_language("de")

            # Should be called twice: once in init, once in set_language
            assert mock_set_lang.call_count == 2
            mock_set_lang.assert_called_with("de")

    @patch("wikipedia.summary")
    def test_get_summary(self, mock_summary):
        """Test get_summary method."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_summary.return_value = "Python is a programming language."

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine(sentences=5)
            result = engine.get_summary("Python", sentences=3)

        mock_summary.assert_called_with(
            "Python", sentences=3, auto_suggest=False
        )
        assert result == "Python is a programming language."

    @patch("wikipedia.page")
    @patch("wikipedia.summary")
    def test_get_page(self, mock_summary, mock_page):
        """Test get_page method."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_page_obj = Mock()
        mock_page_obj.title = "Python"
        mock_page_obj.url = "https://en.wikipedia.org/wiki/Python"
        mock_page_obj.content = "Full content..."
        mock_page_obj.categories = []
        mock_page_obj.references = []
        mock_page_obj.links = []
        mock_page_obj.images = []
        mock_page_obj.sections = []
        mock_page.return_value = mock_page_obj
        mock_summary.return_value = "Python summary"

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine(include_content=True)
            result = engine.get_page("Python")

        assert result["title"] == "Python"
        assert result["content"] == "Full content..."
        assert result["source"] == "Wikipedia"

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_page_error(self, mock_summary, mock_search):
        """Test handling of PageError during preview generation."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = ["Valid Page", "Invalid Page"]
        mock_summary.side_effect = [
            "Valid page content.",
            wikipedia.exceptions.PageError("Invalid Page"),
        ]

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("test query")

        # Should skip the invalid page
        assert len(previews) == 1
        assert previews[0]["title"] == "Valid Page"

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_wikipedia_exception(self, mock_summary, mock_search):
        """Test handling of WikipediaException during preview generation."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = ["Page 1"]
        mock_summary.side_effect = wikipedia.exceptions.WikipediaException(
            "API error"
        )

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("test query")

        # Should handle the exception and return empty
        assert previews == []

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_disambiguation_no_options(
        self, mock_summary, mock_search
    ):
        """Test handling of disambiguation error with no options."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = ["Ambiguous Term"]
        # Create disambiguation error with empty options
        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Ambiguous Term", []
        )
        mock_summary.side_effect = disambiguation_error

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("Ambiguous Term")

        # Should skip the term with no options
        assert len(previews) == 0

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_disambiguation_inner_error(
        self, mock_summary, mock_search
    ):
        """Test handling when disambiguation option also fails."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = ["Term"]
        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Term", ["Option 1", "Option 2"]
        )
        # First call raises disambiguation, second also fails
        mock_summary.side_effect = [
            disambiguation_error,
            Exception("Inner error"),
        ]

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("Term")

        # Should handle inner error gracefully
        assert len(previews) == 0

    @patch("wikipedia.search")
    def test_get_previews_search_exception(self, mock_search):
        """Test handling of exception during search."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.side_effect = Exception("Network error")

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("test query")

        assert previews == []

    @patch("wikipedia.page")
    def test_get_full_content_missing_id(self, mock_page):
        """Test full content retrieval with missing id."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            # Item without id
            relevant_items = [
                {"title": "Some Title", "snippet": "Some snippet"}
            ]

            results = engine._get_full_content(relevant_items)

        # Should return item as-is
        assert len(results) == 1
        assert results[0]["title"] == "Some Title"
        mock_page.assert_not_called()

    @patch("wikipedia.page")
    def test_get_full_content_page_error(self, mock_page):
        """Test full content with PageError falls back to preview."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_page.side_effect = wikipedia.exceptions.PageError("Title")

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            relevant_items = [
                {"id": "Title", "title": "Title", "snippet": "Preview snippet"}
            ]

            results = engine._get_full_content(relevant_items)

        # Should fall back to preview item
        assert len(results) == 1
        assert results[0]["snippet"] == "Preview snippet"
        assert "content" not in results[0]

    @patch("wikipedia.page")
    def test_get_full_content_disambiguation_error(self, mock_page):
        """Test full content with DisambiguationError falls back to preview."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_page.side_effect = wikipedia.exceptions.DisambiguationError(
            "Title", ["Option 1"]
        )

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            relevant_items = [
                {"id": "Title", "title": "Title", "snippet": "Preview"}
            ]

            results = engine._get_full_content(relevant_items)

        # Should fall back to preview
        assert len(results) == 1
        assert "content" not in results[0]

    @patch("wikipedia.page")
    def test_get_full_content_unexpected_error(self, mock_page):
        """Test full content with unexpected error falls back to preview."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_page.side_effect = RuntimeError("Unexpected error")

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            relevant_items = [
                {"id": "Title", "title": "Title", "snippet": "Preview"}
            ]

            results = engine._get_full_content(relevant_items)

        assert len(results) == 1
        assert results[0]["snippet"] == "Preview"

    @patch("wikipedia.summary")
    def test_get_summary_disambiguation(self, mock_summary):
        """Test get_summary handles disambiguation by using first option."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Mercury", ["Mercury (planet)", "Mercury (element)"]
        )
        mock_summary.side_effect = [
            disambiguation_error,
            "Mercury is the closest planet to the Sun.",
        ]

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            result = engine.get_summary("Mercury")

        assert "planet" in result.lower()

    @patch("wikipedia.summary")
    def test_get_summary_disambiguation_no_options_raises(self, mock_summary):
        """Test get_summary raises when disambiguation has no options."""
        import pytest
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Term", []
        )
        mock_summary.side_effect = disambiguation_error

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            with pytest.raises(wikipedia.exceptions.DisambiguationError):
                engine.get_summary("Term")

    @patch("wikipedia.page")
    @patch("wikipedia.summary")
    def test_get_page_disambiguation(self, mock_summary, mock_page):
        """Test get_page handles disambiguation recursively."""
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Mercury", ["Mercury (planet)"]
        )

        mock_page_obj = Mock()
        mock_page_obj.title = "Mercury (planet)"
        mock_page_obj.url = "https://en.wikipedia.org/wiki/Mercury_(planet)"
        mock_page_obj.content = "Mercury is a planet."
        mock_page_obj.categories = []
        mock_page_obj.references = []
        mock_page_obj.links = []
        mock_page_obj.images = []
        mock_page_obj.sections = []

        mock_page.side_effect = [disambiguation_error, mock_page_obj]
        mock_summary.return_value = "Mercury is a planet."

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine(include_content=True)
            result = engine.get_page("Mercury")

        assert result["title"] == "Mercury (planet)"

    @patch("wikipedia.page")
    def test_get_page_disambiguation_no_options_raises(self, mock_page):
        """Test get_page raises when disambiguation has no options."""
        import pytest
        import wikipedia

        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        disambiguation_error = wikipedia.exceptions.DisambiguationError(
            "Term", []
        )
        mock_page.side_effect = disambiguation_error

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()

            with pytest.raises(wikipedia.exceptions.DisambiguationError):
                engine.get_page("Term")

    def test_get_page_without_content(self):
        """Test get_page with include_content=False."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_page_obj = Mock()
        mock_page_obj.title = "Python"
        mock_page_obj.url = "https://en.wikipedia.org/wiki/Python"
        mock_page_obj.content = "Full content..."

        with patch("wikipedia.set_lang"):
            with patch("wikipedia.page", return_value=mock_page_obj):
                with patch("wikipedia.summary", return_value="Python summary"):
                    engine = WikipediaSearchEngine(include_content=False)
                    result = engine.get_page("Python")

        assert result["title"] == "Python"
        # Should not have content when include_content=False
        assert "content" not in result

    def test_get_summary_uses_default_sentences(self):
        """Test get_summary uses instance sentences when not specified."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        with patch("wikipedia.set_lang"):
            with patch("wikipedia.summary", return_value="Summary") as mock:
                engine = WikipediaSearchEngine(sentences=7)
                engine.get_summary("Title")

                mock.assert_called_with(
                    "Title", sentences=7, auto_suggest=False
                )

    @patch("wikipedia.search")
    @patch("wikipedia.summary")
    def test_get_previews_summary_none(self, mock_summary, mock_search):
        """Test preview skipped when summary returns None."""
        from local_deep_research.web_search_engines.engines.search_engine_wikipedia import (
            WikipediaSearchEngine,
        )

        mock_search.return_value = ["Page 1", "Page 2"]
        mock_summary.side_effect = [None, "Valid summary"]

        with patch("wikipedia.set_lang"):
            engine = WikipediaSearchEngine()
            previews = engine._get_previews("query")

        # Should only include the page with valid summary
        assert len(previews) == 1
        assert previews[0]["snippet"] == "Valid summary"
