"""
Tests for the ScaleSerpSearchEngine class.

Tests cover:
- Initialization and configuration
- API key handling
- Caching configuration
- Preview generation
- Full content retrieval
- Rate limiting
- Knowledge graph handling
"""

from unittest.mock import Mock, patch
import pytest


class TestScaleSerpSearchEngineInit:
    """Tests for ScaleSerpSearchEngine initialization."""

    def test_init_with_api_key(self):
        """Initialize with API key."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-api-key")

        assert engine.api_key == "test-api-key"
        assert engine.max_results == 10
        assert engine.location == "United States"
        assert engine.language == "en"
        assert engine.device == "desktop"
        assert engine.safe_search is True
        assert engine.enable_cache is True
        assert engine.base_url == "https://api.scaleserp.com/search"

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

        engine = ScaleSerpSearchEngine(api_key="test-key", max_results=50)

        assert engine.max_results == 50

    def test_init_with_custom_location(self):
        """Initialize with custom location."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(
            api_key="test-key", location="London,England,United Kingdom"
        )

        assert engine.location == "London,England,United Kingdom"

    def test_init_with_custom_language(self):
        """Initialize with custom language."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key", language="es")

        assert engine.language == "es"

    def test_init_with_mobile_device(self):
        """Initialize with mobile device."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key", device="mobile")

        assert engine.device == "mobile"

    def test_init_with_safe_search_disabled(self):
        """Initialize with safe_search disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key", safe_search=False)

        assert engine.safe_search is False

    def test_init_with_cache_disabled(self):
        """Initialize with caching disabled."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key", enable_cache=False)

        assert engine.enable_cache is False

    def test_init_without_api_key_raises(self):
        """Initialize without API key raises ValueError."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

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

    def test_init_with_api_key_from_settings(self):
        """Initialize with API key from settings."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(
            settings_snapshot={
                "search.engine.web.scaleserp.api_key": "settings-api-key"
            }
        )

        assert engine.api_key == "settings-api-key"

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

        mock_llm = Mock()
        engine = ScaleSerpSearchEngine(api_key="test-key", llm=mock_llm)

        assert engine.llm is mock_llm


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

    def test_get_previews_returns_results(self):
        """Get previews returns formatted results."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "request_info": {"cached": False},
            "organic_results": [
                {
                    "position": 1,
                    "title": "Result 1",
                    "link": "https://example1.com/page",
                    "snippet": "Snippet 1",
                },
                {
                    "position": 2,
                    "title": "Result 2",
                    "link": "https://example2.com/page",
                    "snippet": "Snippet 2",
                },
            ],
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert len(previews) == 2
            assert previews[0]["title"] == "Result 1"
            assert previews[0]["link"] == "https://example1.com/page"
            assert previews[0]["displayed_link"] == "example1.com"
            assert previews[0]["from_cache"] is False

    def test_get_previews_with_null_link_keeps_results(self):
        """A JSON null link in one result must not drop the whole result set.

        Regression test: the ``fallback=link[:50]`` argument is evaluated
        eagerly, so a None link raised TypeError inside the result loop,
        which the outer exception handler turned into an empty preview list.
        """
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "request_info": {"cached": False},
            "organic_results": [
                {
                    "position": 1,
                    "title": "Result with null link",
                    "link": None,
                    "snippet": "Snippet 1",
                },
                {
                    "position": 2,
                    "title": "Result 2",
                    "link": "https://example2.com/page",
                    "snippet": "Snippet 2",
                },
            ],
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert len(previews) == 2
            assert previews[0]["link"] == ""
            assert previews[0]["displayed_link"] == ""
            assert previews[1]["displayed_link"] == "example2.com"

    def test_get_previews_with_cache_status(self):
        """Get previews includes cache status."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "request_info": {"cached": True},
            "organic_results": [
                {
                    "position": 1,
                    "title": "Result",
                    "link": "https://example.com",
                    "snippet": "Test",
                }
            ],
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert previews[0]["from_cache"] is True

    def test_get_previews_with_knowledge_graph(self):
        """Get previews stores knowledge graph."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "request_info": {},
            "organic_results": [],
            "knowledge_graph": {"title": "Test Entity", "type": "Organization"},
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            engine._get_previews("test query")

            assert hasattr(engine, "_knowledge_graph")
            assert engine._knowledge_graph["title"] == "Test Entity"

    def test_get_previews_with_rich_snippets(self):
        """Get previews includes rich snippets."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "request_info": {},
            "organic_results": [
                {
                    "position": 1,
                    "title": "Result",
                    "link": "https://example.com",
                    "snippet": "Test",
                    "rich_snippet": {"rating": 4.5},
                    "date": "2024-01-15",
                    "sitelinks": [{"title": "About"}],
                }
            ],
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert "rich_snippet" in previews[0]
            assert "date" in previews[0]
            assert "sitelinks" in previews[0]

    def test_get_previews_rate_limit_error(self):
        """Get previews raises RateLimitError on 429."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )
        from local_deep_research.web_search_engines.rate_limiting import (
            RateLimitError,
        )

        mock_response = Mock()
        mock_response.status_code = 429
        mock_response.text = "Rate limit exceeded"

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")

            with pytest.raises(RateLimitError):
                engine._get_previews("test query")

    def test_get_previews_empty_results(self):
        """Get previews handles empty results."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "request_info": {},
            "organic_results": [],
        }
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            return_value=mock_response,
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert previews == []

    def test_get_previews_request_exception(self):
        """Get previews handles request exceptions."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )
        import requests

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_scaleserp.safe_get",
            side_effect=requests.exceptions.RequestException(
                "Connection error"
            ),
        ):
            engine = ScaleSerpSearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert previews == []


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

    def test_get_full_content_returns_items(self):
        """Get full content returns processed items."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key")

        items = [
            {
                "title": "Result",
                "link": "https://example.com",
                "_full_result": {"title": "Result", "extra": "data"},
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        assert results[0]["extra"] == "data"
        assert "_full_result" not in results[0]

    def test_get_full_content_includes_knowledge_graph(self):
        """Get full content includes knowledge graph in first result."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key")
        engine._knowledge_graph = {"title": "Test Entity"}

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

        results = engine._get_full_content(items)

        assert "knowledge_graph" in results[0]
        assert results[0]["knowledge_graph"]["title"] == "Test Entity"

    def test_get_full_content_extracts_full_result_with_knowledge_graph(self):
        """Get full content extracts _full_result via super() and adds knowledge graph."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key")
        engine._knowledge_graph = {
            "title": "Test Entity",
            "type": "Organization",
        }

        items = [
            {
                "title": "Result",
                "link": "https://example.com",
                "_full_result": {
                    "title": "Result",
                    "link": "https://example.com",
                    "snippet": "Full snippet",
                    "position": 1,
                },
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        # Verify _full_result extraction from base class
        assert results[0]["snippet"] == "Full snippet"
        assert results[0]["position"] == 1
        assert "_full_result" not in results[0]
        # Verify knowledge graph added by override
        assert results[0]["knowledge_graph"]["title"] == "Test Entity"
        assert results[0]["knowledge_graph"]["type"] == "Organization"

    def test_get_full_content_no_knowledge_graph_on_second_result(self):
        """Get full content only adds knowledge graph to first result."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key")
        engine._knowledge_graph = {"title": "Test Entity"}

        items = [
            {"title": "Result 1", "link": "https://example1.com"},
            {"title": "Result 2", "link": "https://example2.com"},
        ]

        results = engine._get_full_content(items)

        assert "knowledge_graph" in results[0]
        assert "knowledge_graph" not in results[1]


class TestRun:
    """Tests for run method."""

    def test_run_returns_results(self):
        """Run returns search results."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key")

        with patch.object(
            engine,
            "_get_previews",
            return_value=[
                {
                    "id": 0,
                    "title": "Result",
                    "snippet": "Snippet",
                    "link": "https://example.com",
                }
            ],
        ):
            with patch.object(
                engine,
                "_get_full_content",
                return_value=[{"title": "Result", "content": "Full"}],
            ):
                results = engine.run("test query")

                assert len(results) == 1

    def test_run_cleans_up_attributes(self):
        """Run cleans up temporary attributes."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        engine = ScaleSerpSearchEngine(api_key="test-key")
        engine._search_results = [{"test": "data"}]
        engine._knowledge_graph = {"title": "Test"}

        with patch.object(engine, "_get_previews", return_value=[]):
            engine.run("test query")

            assert not hasattr(engine, "_search_results")
            assert not hasattr(engine, "_knowledge_graph")


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

    def test_is_public(self):
        """ScaleSerpSearchEngine is marked as public."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        assert ScaleSerpSearchEngine.is_public is True

    def test_is_generic(self):
        """ScaleSerpSearchEngine is marked as generic."""
        from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
            ScaleSerpSearchEngine,
        )

        assert ScaleSerpSearchEngine.is_generic is True
