"""
Tests for the TavilySearchEngine class.

Tests cover:
- Initialization and configuration
- API key handling
- Preview generation
- Full content retrieval
- Rate limit error handling
- Run method
"""

from unittest.mock import Mock, patch
import pytest


class TestTavilySearchEngineInit:
    """Tests for TavilySearchEngine initialization."""

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

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

        assert engine.api_key == "test-api-key"
        assert engine.max_results == 10
        assert engine.search_depth == "basic"
        assert engine.include_full_content is True

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

        engine = TavilySearchEngine(api_key="test-key", max_results=25)

        assert engine.max_results == 25

    def test_init_with_custom_search_depth(self):
        """Initialize with custom search_depth."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(api_key="test-key", search_depth="advanced")

        assert engine.search_depth == "advanced"

    def test_init_with_domain_filters(self):
        """Initialize with domain filters."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            api_key="test-key",
            include_domains=["example.com", "test.com"],
            exclude_domains=["spam.com"],
        )

        assert engine.include_domains == ["example.com", "test.com"]
        assert engine.exclude_domains == ["spam.com"]

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

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

    def test_init_with_api_key_from_settings(self):
        """Initialize with API key from settings snapshot."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            settings_snapshot={
                "search.engine.web.tavily.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_tavily import (
            TavilySearchEngine,
        )

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

        assert engine.llm is mock_llm

    def test_init_with_include_full_content_false(self):
        """Initialize with include_full_content=False."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            api_key="test-key", include_full_content=False
        )

        assert engine.include_full_content is False


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_tavily import (
            TavilySearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "results": [
                {
                    "title": "Result 1",
                    "url": "https://example1.com",
                    "content": "Snippet 1",
                },
                {
                    "title": "Result 2",
                    "url": "https://example2.com",
                    "content": "Snippet 2",
                },
            ]
        }

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_tavily.safe_post",
            return_value=mock_response,
        ):
            engine = TavilySearchEngine(api_key="test-key")
            previews = engine._get_previews("test query")

            assert len(previews) == 2
            assert previews[0]["title"] == "Result 1"
            assert previews[0]["snippet"] == "Snippet 1"
            assert previews[0]["link"] == "https://example1.com"

    def test_get_previews_with_domain_filters(self):
        """Get previews sends domain filters to API."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"results": []}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_tavily.safe_post",
            return_value=mock_response,
        ) as mock_post:
            engine = TavilySearchEngine(
                api_key="test-key",
                include_domains=["example.com"],
                exclude_domains=["spam.com"],
            )
            engine._get_previews("test query")

            # Check that domain filters were sent
            call_args = mock_post.call_args
            payload = call_args[1]["json"]
            assert payload["include_domains"] == ["example.com"]
            assert payload["exclude_domains"] == ["spam.com"]

    def test_get_previews_rate_limit_error(self):
        """Get previews raises RateLimitError on 429."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )
        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_tavily.safe_post",
            return_value=mock_response,
        ):
            engine = TavilySearchEngine(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_tavily import (
            TavilySearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"results": []}

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_tavily.safe_post",
            return_value=mock_response,
        ):
            engine = TavilySearchEngine(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_tavily import (
            TavilySearchEngine,
        )
        import requests

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

            assert previews == []

    def test_get_previews_request_exception_with_rate_limit(self):
        """Get previews raises RateLimitError when RequestException contains rate limit message."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )
        from local_deep_research.web_search_engines.rate_limiting import (
            RateLimitError,
        )
        import requests

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_tavily.safe_post",
            side_effect=requests.exceptions.RequestException(
                "rate limit exceeded"
            ),
        ):
            engine = TavilySearchEngine(api_key="test-key")

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

    def test_get_previews_unexpected_error(self):
        """Get previews handles unexpected errors."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.side_effect = Exception("Parse error")
        mock_response.raise_for_status = Mock()

        with patch(
            "local_deep_research.web_search_engines.engines.search_engine_tavily.safe_post",
            return_value=mock_response,
        ):
            engine = TavilySearchEngine(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_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            api_key="test-key", include_full_content=False
        )

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

        results = engine._get_full_content(items)

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

    def test_get_full_content_without_full_result(self):
        """Get full content handles items without _full_result."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            api_key="test-key", include_full_content=False
        )

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

        results = engine._get_full_content(items)

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

    def test_get_full_content_uses_raw_content_when_enabled(self):
        """Get full content maps raw_content to content when include_full_content=True."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            api_key="test-key", include_full_content=True
        )

        items = [
            {
                "title": "Result",
                "link": "https://example.com",
                "_full_result": {
                    "title": "Result",
                    "url": "https://example.com",
                    "content": "Short snippet",
                    "raw_content": "Full raw content from Tavily API",
                },
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        assert results[0]["content"] == "Full raw content from Tavily API"

    def test_get_full_content_ignores_raw_content_when_disabled(self):
        """Get full content does NOT map raw_content when include_full_content=False."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

        engine = TavilySearchEngine(
            api_key="test-key", include_full_content=False
        )

        items = [
            {
                "title": "Result",
                "link": "https://example.com",
                "_full_result": {
                    "title": "Result",
                    "url": "https://example.com",
                    "content": "Short snippet",
                    "raw_content": "Full raw content from Tavily API",
                },
            }
        ]

        results = engine._get_full_content(items)

        assert len(results) == 1
        # raw_content should be in the result (from _full_result extraction) but NOT mapped to content
        assert results[0]["content"] == "Short snippet"


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_tavily import (
            TavilySearchEngine,
        )

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

        with patch.object(
            engine,
            "_get_previews",
            return_value=[
                {
                    "id": "https://example.com",
                    "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_handles_empty_results(self):
        """Run handles empty results."""
        from local_deep_research.web_search_engines.engines.search_engine_tavily import (
            TavilySearchEngine,
        )

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

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

            assert results == []


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

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

        assert TavilySearchEngine.is_public is True

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

        assert TavilySearchEngine.is_generic is True
