"""
Tests for uncovered code paths in ScaleSerpSearchEngine.

Targets:
- _get_previews: URL parsing fallback, cache detection, knowledge graph, related searches/questions
- _get_previews: rich snippets, dates, sitelinks, safe search
- _get_previews: rate limit error, request exception, unexpected exception
- _get_full_content: knowledge graph inclusion
"""

from unittest.mock import Mock, patch

import pytest
import requests

from local_deep_research.web_search_engines.engines.search_engine_scaleserp import (
    ScaleSerpSearchEngine,
)
from local_deep_research.web_search_engines.rate_limiting import RateLimitError

MODULE = (
    "local_deep_research.web_search_engines.engines.search_engine_scaleserp"
)


@pytest.fixture
def engine():
    eng = ScaleSerpSearchEngine(
        api_key="test-key", max_results=5, safe_search=True
    )
    eng.rate_tracker = Mock()
    eng.rate_tracker.apply_rate_limit.return_value = 0
    return eng


def _mock_response(status_code=200, json_data=None):
    resp = Mock()
    resp.status_code = status_code
    resp.json.return_value = json_data or {}
    resp.raise_for_status = Mock()
    if status_code >= 400:
        resp.raise_for_status.side_effect = Exception(f"HTTP {status_code}")
    return resp


class TestGetPreviews:
    @patch(f"{MODULE}.safe_get")
    def test_basic_results(self, mock_get, engine):
        """Returns formatted previews from organic results."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "Test Result",
                        "link": "https://example.com/page",
                        "snippet": "A test snippet",
                        "position": 1,
                    }
                ],
                "request_info": {"cached": False},
            },
        )

        previews = engine._get_previews("test query")

        assert len(previews) == 1
        assert previews[0]["title"] == "Test Result"
        assert previews[0]["link"] == "https://example.com/page"
        assert previews[0]["displayed_link"] == "example.com"

    @patch(f"{MODULE}.safe_get")
    def test_url_parse_fallback(self, mock_get, engine):
        """Falls back to truncated URL when parsing fails."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "Bad URL",
                        "link": "",  # Empty link
                        "snippet": "test",
                    }
                ],
                "request_info": {},
            },
        )

        previews = engine._get_previews("test")
        assert len(previews) == 1
        assert previews[0]["displayed_link"] == ""

    @patch(f"{MODULE}.safe_get")
    def test_cached_results_detected(self, mock_get, engine):
        """Detects cached results from request_info."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "Cached",
                        "link": "https://example.com",
                        "snippet": "s",
                    }
                ],
                "request_info": {"cached": True},
            },
        )

        previews = engine._get_previews("test")
        assert previews[0]["from_cache"] is True

    @patch(f"{MODULE}.safe_get")
    def test_knowledge_graph_stored(self, mock_get, engine):
        """Knowledge graph data is stored from response."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "T",
                        "link": "https://example.com",
                        "snippet": "s",
                    }
                ],
                "knowledge_graph": {
                    "title": "Python",
                    "type": "Programming Language",
                },
                "request_info": {},
            },
        )

        engine._get_previews("python")
        assert engine._knowledge_graph is not None
        assert engine._knowledge_graph["title"] == "Python"

    @patch(f"{MODULE}.safe_get")
    def test_related_searches_stored(self, mock_get, engine):
        """Related searches are stored from response."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [],
                "related_searches": [{"query": "python tutorial"}],
                "request_info": {},
            },
        )

        engine._get_previews("python")
        assert engine._related_searches is not None

    @patch(f"{MODULE}.safe_get")
    def test_related_questions_stored(self, mock_get, engine):
        """Related questions (PAA) are stored from response."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [],
                "related_questions": [{"question": "What is Python?"}],
                "request_info": {},
            },
        )

        engine._get_previews("python")
        assert engine._related_questions is not None

    @patch(f"{MODULE}.safe_get")
    def test_rich_snippet_included(self, mock_get, engine):
        """Rich snippets are included in preview."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "T",
                        "link": "https://example.com",
                        "snippet": "s",
                        "rich_snippet": {"rating": 4.5},
                    }
                ],
                "request_info": {},
            },
        )

        previews = engine._get_previews("test")
        assert "rich_snippet" in previews[0]
        assert previews[0]["rich_snippet"]["rating"] == 4.5

    @patch(f"{MODULE}.safe_get")
    def test_date_included(self, mock_get, engine):
        """Dates are included in preview."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "T",
                        "link": "https://example.com",
                        "snippet": "s",
                        "date": "2024-01-15",
                    }
                ],
                "request_info": {},
            },
        )

        previews = engine._get_previews("test")
        assert previews[0]["date"] == "2024-01-15"

    @patch(f"{MODULE}.safe_get")
    def test_sitelinks_included(self, mock_get, engine):
        """Sitelinks are included in preview."""
        mock_get.return_value = _mock_response(
            200,
            {
                "organic_results": [
                    {
                        "title": "T",
                        "link": "https://example.com",
                        "snippet": "s",
                        "sitelinks": [{"title": "About"}],
                    }
                ],
                "request_info": {},
            },
        )

        previews = engine._get_previews("test")
        assert "sitelinks" in previews[0]

    @patch(f"{MODULE}.safe_get")
    def test_rate_limit_raises(self, mock_get, engine):
        """RateLimitError is re-raised."""
        mock_get.return_value = _mock_response(429)
        engine._raise_if_rate_limit = Mock(side_effect=RateLimitError("429"))

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

    @patch(f"{MODULE}.safe_get")
    def test_request_exception_returns_empty(self, mock_get, engine):
        """RequestException returns empty list."""
        mock_get.side_effect = requests.exceptions.ConnectionError("fail")

        result = engine._get_previews("test")
        assert result == []

    @patch(f"{MODULE}.safe_get")
    def test_unexpected_exception_returns_empty(self, mock_get, engine):
        """Unexpected exception returns empty list."""
        mock_get.side_effect = TypeError("unexpected")

        result = engine._get_previews("test")
        assert result == []

    @patch(f"{MODULE}.safe_get")
    def test_per_query_attributes_reset(self, mock_get, engine):
        """Per-query attributes are reset before each search."""
        engine._knowledge_graph = {"old": "data"}
        engine._related_searches = ["old"]
        engine._related_questions = ["old"]

        mock_get.return_value = _mock_response(
            200, {"organic_results": [], "request_info": {}}
        )

        engine._get_previews("new query")

        # Should be reset since response doesn't contain them
        assert engine._knowledge_graph is None
        assert engine._related_searches is None
        assert engine._related_questions is None


class TestGetFullContent:
    def test_includes_knowledge_graph(self, engine):
        """Full content includes knowledge graph in first result."""
        engine._knowledge_graph = {"title": "Python", "type": "Language"}

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

        with patch.object(
            ScaleSerpSearchEngine.__bases__[0],
            "_get_full_content",
            return_value=[{"title": "Result 1", "content": "text"}],
        ):
            results = engine._get_full_content(items)

        assert results[0]["knowledge_graph"]["title"] == "Python"

    def test_no_knowledge_graph(self, engine):
        """Full content works without knowledge graph."""
        engine._knowledge_graph = None

        items = [{"title": "Result 1"}]

        with patch.object(
            ScaleSerpSearchEngine.__bases__[0],
            "_get_full_content",
            return_value=[{"title": "Result 1"}],
        ):
            results = engine._get_full_content(items)

        assert results[0].get("knowledge_graph") is None
