"""
Comprehensive tests for the SerpAPI search engine (Google via SerpAPI).
Tests initialization, search functionality, and result formatting.

Note: These tests mock the SerpAPIWrapper to avoid requiring an API key.
"""

import pytest
from unittest.mock import Mock


@pytest.fixture(autouse=True)
def mock_serpapi_wrapper(monkeypatch):
    """Mock SerpAPIWrapper to avoid LangChain initialization."""
    mock_wrapper = Mock()
    mock_wrapper.return_value = mock_wrapper
    monkeypatch.setattr(
        "local_deep_research.web_search_engines.engines.search_engine_serpapi.SerpAPIWrapper",
        mock_wrapper,
    )
    return mock_wrapper


class TestSerpAPISearchEngineInit:
    """Tests for SerpAPI search engine initialization."""

    def test_init_default_values(self):
        """Test initialization with default values."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key")

        assert engine.max_results == 10
        assert engine.is_public is True
        assert engine.is_generic is True

    def test_init_with_custom_max_results(self):
        """Test initialization with custom max results."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key", max_results=25)
        assert engine.max_results == 25

    def test_init_without_api_key_raises_error(self, monkeypatch):
        """Test that initialization without API key raises ValueError."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        monkeypatch.setattr(
            "local_deep_research.config.search_config.get_setting_from_snapshot",
            Mock(return_value=None),
        )

        with pytest.raises(
            ValueError, match="No valid API key found for SerpAPI"
        ):
            SerpAPISearchEngine()

    def test_init_with_region(self):
        """Test initialization with custom region."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key", region="gb")
        # Engine should be created successfully
        assert engine is not None

    def test_init_with_time_period(self):
        """Test initialization with time period filter."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key", time_period="m")
        assert engine is not None

    def test_init_with_safe_search_disabled(self):
        """Test initialization with safe search disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key", safe_search=False)
        assert engine is not None


class TestSerpAPIEngineType:
    """Tests for SerpAPI engine type identification."""

    def test_engine_type_set(self):
        """Test that engine type is properly set."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key")
        assert "serpapi" in engine.engine_type.lower()

    def test_engine_is_public(self):
        """Test that engine is marked as public."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key")
        assert engine.is_public is True

    def test_engine_is_generic(self):
        """Test that engine is marked as generic."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key")
        assert engine.is_generic is True


class TestSerpAPILanguageMapping:
    """Tests for SerpAPI language code mapping."""

    def test_default_language_mapping(self):
        """Test that default language mapping includes common languages."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        # Create engine with each supported language
        languages = ["english", "spanish", "french", "german", "portuguese"]
        for lang in languages:
            engine = SerpAPISearchEngine(
                api_key="test_key", search_language=lang
            )
            assert engine is not None

    def test_custom_language_mapping(self):
        """Test custom language mapping."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        custom_mapping = {"custom": "cu"}
        engine = SerpAPISearchEngine(
            api_key="test_key",
            search_language="custom",
            language_code_mapping=custom_mapping,
        )
        assert engine is not None


class TestSerpAPISearchExecution:
    """Tests for SerpAPI search execution."""

    @pytest.fixture
    def engine(self, mock_serpapi_wrapper):
        """Create a SerpAPI engine with mocked wrapper."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        engine = SerpAPISearchEngine(api_key="test_key", max_results=10)
        return engine

    def test_get_previews_success(self, engine):
        """Test successful preview retrieval."""
        engine.engine.results = Mock(
            return_value={
                "organic_results": [
                    {
                        "position": 1,
                        "title": "Test Result",
                        "link": "https://example.com/page",
                        "snippet": "This is a test snippet.",
                        "displayed_link": "example.com",
                    },
                    {
                        "position": 2,
                        "title": "Second Result",
                        "link": "https://test.org/article",
                        "snippet": "Another snippet.",
                        "displayed_link": "test.org",
                    },
                ]
            }
        )

        previews = engine._get_previews("test query")

        assert len(previews) == 2
        assert previews[0]["title"] == "Test Result"
        assert previews[0]["link"] == "https://example.com/page"
        assert previews[0]["snippet"] == "This is a test snippet."
        assert previews[0]["position"] == 1

    def test_get_previews_empty_results(self, engine):
        """Test preview retrieval with no results."""
        engine.engine.results = Mock(return_value={"organic_results": []})

        previews = engine._get_previews("nonexistent topic xyz123")

        assert previews == []

    def test_get_previews_handles_exception(self, engine):
        """Test that exceptions are handled gracefully."""
        engine.engine.results = Mock(side_effect=Exception("API error"))

        previews = engine._get_previews("test query")

        assert previews == []

    def test_get_previews_stores_results(self, engine):
        """Test that previews are stored for later retrieval."""
        engine.engine.results = Mock(
            return_value={
                "organic_results": [
                    {
                        "position": 1,
                        "title": "Test",
                        "link": "https://example.com",
                        "snippet": "Test",
                    }
                ]
            }
        )

        engine._get_previews("test query")

        assert hasattr(engine, "_search_results")
        assert len(engine._search_results) == 1


class TestSerpAPIFullContent:
    """Tests for SerpAPI full content retrieval."""

    @pytest.fixture
    def engine(self, mock_serpapi_wrapper):
        """Create a SerpAPI engine."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        return SerpAPISearchEngine(api_key="test_key")

    def test_get_full_content_with_full_result(self, engine, monkeypatch):
        """Test full content retrieval with _full_result available."""
        # Mock to simulate SEARCH_SNIPPETS_ONLY not existing
        import local_deep_research.config.search_config as search_config_module

        if hasattr(search_config_module, "SEARCH_SNIPPETS_ONLY"):
            monkeypatch.delattr(
                "local_deep_research.config.search_config.SEARCH_SNIPPETS_ONLY",
                raising=False,
            )

        items = [
            {
                "title": "Test Result",
                "link": "https://example.com",
                "snippet": "Test snippet",
                "_full_result": {
                    "title": "Test Result",
                    "link": "https://example.com",
                    "snippet": "Test snippet",
                    "extra_data": "additional info",
                },
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        assert results[0]["title"] == "Test Result"
        assert "_full_result" not in results[0]

    def test_get_full_content_without_full_result(self, engine, monkeypatch):
        """Test full content retrieval when _full_result is not available."""
        import local_deep_research.config.search_config as search_config_module

        if hasattr(search_config_module, "SEARCH_SNIPPETS_ONLY"):
            monkeypatch.delattr(
                "local_deep_research.config.search_config.SEARCH_SNIPPETS_ONLY",
                raising=False,
            )

        items = [
            {
                "title": "Test Result",
                "link": "https://example.com",
                "snippet": "Test snippet",
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        assert results[0]["title"] == "Test Result"


class TestSerpAPIRun:
    """Tests for SerpAPI run method."""

    @pytest.fixture
    def engine(self, mock_serpapi_wrapper):
        """Create a SerpAPI engine."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        return SerpAPISearchEngine(api_key="test_key")

    def test_run_cleans_up_search_results(self, engine):
        """Test that run method cleans up _search_results."""
        engine.engine.results = Mock(
            return_value={
                "organic_results": [
                    {
                        "position": 1,
                        "title": "Test",
                        "link": "http://test.com",
                        "snippet": "Test",
                    }
                ]
            }
        )

        # Run search
        engine.run("test query")

        # _search_results should be cleaned up
        assert not hasattr(engine, "_search_results")


class TestSerpAPIFullContentRetrieval:
    """Tests for SerpAPI full content retrieval feature."""

    def test_init_with_full_content_enabled(
        self, mock_serpapi_wrapper, monkeypatch
    ):
        """Test initialization with full content retrieval enabled."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        # Mock FullSearchResults import
        mock_full_search = Mock()
        monkeypatch.setattr(
            "local_deep_research.web_search_engines.engines.full_search.FullSearchResults",
            mock_full_search,
        )

        engine = SerpAPISearchEngine(
            api_key="test_key", include_full_content=True, llm=Mock()
        )
        assert engine.include_full_content is True
        assert hasattr(engine, "full_search")
        mock_full_search.assert_called_once()

    def test_init_full_content_disabled_on_import_error(
        self, mock_serpapi_wrapper, monkeypatch
    ):
        """Test that full content is disabled if FullSearchResults import fails."""
        from local_deep_research.web_search_engines.engines.search_engine_serpapi import (
            SerpAPISearchEngine,
        )

        # The default behavior without FullSearchResults should work
        engine = SerpAPISearchEngine(
            api_key="test_key", include_full_content=False
        )
        assert engine.include_full_content is False
