"""
Tests for the FullSearchResults class.

Tests cover:
- Initialization and configuration
- URL quality checking with LLM
- Full search workflow
"""

from unittest.mock import Mock, patch
import pytest


class TestFullSearchResultsInit:
    """Tests for FullSearchResults initialization."""

    def test_init_with_defaults(self):
        """Initialize with default values."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

        assert engine.llm is mock_llm
        assert engine.web_search is mock_web_search
        assert engine.output_format == "list"
        assert engine.language == "English"
        assert engine.max_results == 10
        assert engine.region == "wt-wt"
        assert engine.time == "y"
        assert engine.safesearch == "Moderate"

    def test_init_with_custom_values(self):
        """Initialize with custom values."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()

        engine = FullSearchResults(
            llm=mock_llm,
            web_search=mock_web_search,
            output_format="json",
            language="German",
            max_results=25,
            region="de-de",
            time="m",
            safesearch="Off",
        )

        assert engine.output_format == "json"
        assert engine.language == "German"
        assert engine.max_results == 25
        assert engine.region == "de-de"
        assert engine.time == "m"
        assert engine.safesearch == "Off"


class TestCheckUrls:
    """Tests for check_urls method."""

    def test_check_urls_empty_results(self):
        """Check URLs returns empty for empty results."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

        results = engine.check_urls([], "test query")

        assert results == []

    def test_check_urls_filters_results(self):
        """Check URLs filters results based on LLM response."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(content="[0, 2]")
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

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

        filtered = engine.check_urls(results, "test query")

        assert len(filtered) == 2
        assert filtered[0]["title"] == "Result 1"
        assert filtered[1]["title"] == "Result 3"

    def test_check_urls_handles_think_tags(self):
        """Check URLs handles response with think tags."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(
            content="<think>reasoning</think>[1]"
        )
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

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

        filtered = engine.check_urls(results, "test query")

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

    def test_check_urls_exception(self):
        """Check URLs falls back to original results on exception."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_llm.invoke.side_effect = Exception("LLM error")
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

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

        filtered = engine.check_urls(results, "test query")

        assert filtered == results

    def test_check_urls_invalid_json(self):
        """Check URLs returns empty on invalid JSON response."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(content="not valid json")
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

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

        filtered = engine.check_urls(results, "test query")

        assert filtered == []


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

    def test_run_returns_results(self):
        """Run returns results with full content via batch_fetch_and_extract."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()
        mock_web_search.invoke.return_value = [
            {"link": "https://example.com/1", "title": "Result 1"},
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.full_search.QUALITY_CHECK_DDG_URLS",
            False,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.full_search.validate_url",
                return_value=True,
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.full_search.batch_fetch_and_extract",
                    return_value={"https://example.com/1": "Fetched content"},
                ):
                    engine = FullSearchResults(
                        llm=mock_llm, web_search=mock_web_search
                    )
                    results = engine.run("test query")

        assert len(results) == 1
        assert results[0]["full_content"] == "Fetched content"

    def test_run_with_url_filtering(self):
        """Run filters URLs when QUALITY_CHECK_DDG_URLS is True."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_llm.invoke.return_value = Mock(content="[0]")
        mock_web_search = Mock()
        mock_web_search.invoke.return_value = [
            {"link": "https://example.com/1", "title": "Result 1"},
            {"link": "https://example.com/2", "title": "Result 2"},
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.full_search.QUALITY_CHECK_DDG_URLS",
            True,
        ):
            with patch(
                "local_deep_research.web_search_engines.engines.full_search.validate_url",
                return_value=True,
            ):
                with patch(
                    "local_deep_research.web_search_engines.engines.full_search.batch_fetch_and_extract",
                    return_value={"https://example.com/1": "Content"},
                ):
                    engine = FullSearchResults(
                        llm=mock_llm, web_search=mock_web_search
                    )
                    results = engine.run("test query")

        # Only one result should pass the LLM filter
        assert len(results) == 1

    def test_run_no_valid_links(self):
        """Run returns empty when no valid links."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()
        mock_web_search.invoke.return_value = [
            {"title": "Result without link"},
        ]

        with patch(
            "local_deep_research.web_search_engines.engines.full_search.QUALITY_CHECK_DDG_URLS",
            False,
        ):
            engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)
            results = engine.run("test query")

            assert results == []

    def test_run_invalid_search_results_format(self):
        """Run raises error for invalid search results format."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()
        mock_web_search.invoke.return_value = "not a list"

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

        with pytest.raises(
            ValueError, match="Expected the search results in list format"
        ):
            engine.run("test query")


class TestInvoke:
    """Tests for invoke method."""

    def test_invoke_delegates_to_run(self):
        """Invoke delegates to run method."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

        with patch.object(
            engine, "run", return_value=[{"result": "test"}]
        ) as mock_run:
            result = engine.invoke("test query")

            mock_run.assert_called_once_with("test query")
            assert result == [{"result": "test"}]


class TestCallable:
    """Tests for __call__ method."""

    def test_callable_delegates_to_invoke(self):
        """Calling instance delegates to invoke method."""
        from local_deep_research.web_search_engines.engines.full_search import (
            FullSearchResults,
        )

        mock_llm = Mock()
        mock_web_search = Mock()

        engine = FullSearchResults(llm=mock_llm, web_search=mock_web_search)

        with patch.object(
            engine, "invoke", return_value=[{"result": "test"}]
        ) as mock_invoke:
            result = engine("test query")

            mock_invoke.assert_called_once_with("test query")
            assert result == [{"result": "test"}]
