"""Tests for search_config module."""

from unittest.mock import MagicMock, patch


from local_deep_research.config.search_config import (
    get_search,
    QUALITY_CHECK_DDG_URLS,
)


class TestQualityCheckConstant:
    """Tests for QUALITY_CHECK_DDG_URLS constant."""

    def test_is_boolean(self):
        """Should be a boolean value."""
        assert isinstance(QUALITY_CHECK_DDG_URLS, bool)


class TestGetSearch:
    """Tests for get_search function."""

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_creates_search_engine(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should create search engine via factory."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_llm = MagicMock()
        mock_get_llm.return_value = mock_llm
        mock_engine = MagicMock()
        mock_factory.return_value = mock_engine

        result = get_search()

        assert result is mock_engine
        mock_factory.assert_called_once()

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_uses_provided_search_tool(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should use provided search_tool argument."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = MagicMock()

        get_search(search_tool="duckduckgo")

        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["search_tool"] == "duckduckgo"

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_uses_provided_llm_instance(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should use provided llm_instance instead of getting new one."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_factory.return_value = MagicMock()
        custom_llm = MagicMock()

        get_search(llm_instance=custom_llm)

        # Should not call get_llm
        mock_get_llm.assert_not_called()
        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["llm_instance"] is custom_llm

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_extracts_value_from_dict_tool(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should extract value when search.tool is a dict."""

        def get_setting_side_effect(key, default, **kwargs):
            if key == "search.tool":
                return {"value": "wikipedia"}
            return default

        mock_get_setting.side_effect = get_setting_side_effect
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = MagicMock()

        get_search()

        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["search_tool"] == "wikipedia"

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_adds_username_to_snapshot(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should add username to settings snapshot."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = MagicMock()

        get_search(username="testuser", settings_snapshot={"existing": "value"})

        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["settings_snapshot"]["_username"] == "testuser"
        assert call_kwargs["settings_snapshot"]["existing"] == "value"

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_creates_snapshot_with_username_only(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should create snapshot with just username if none provided."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = MagicMock()

        get_search(username="testuser")

        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["settings_snapshot"]["_username"] == "testuser"

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_passes_programmatic_mode(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should pass programmatic_mode to factory."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = MagicMock()

        get_search(programmatic_mode=True)

        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["programmatic_mode"] is True

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_passes_all_search_params(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should pass all search parameters to factory."""
        settings = {
            "search.tool": "searxng",
            "search.max_results": 20,
            "search.region": "us-en",
            "search.time_period": "w",
            "search.safe_search": False,
            "search.snippets_only": False,
            "search.search_language": "German",
            "search.max_filtered_results": 10,
        }

        def get_setting_side_effect(key, default, **kwargs):
            return settings.get(key, default)

        mock_get_setting.side_effect = get_setting_side_effect
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = MagicMock()

        get_search()

        call_kwargs = mock_factory.call_args[1]
        assert call_kwargs["max_results"] == 20
        assert call_kwargs["region"] == "us-en"
        assert call_kwargs["time_period"] == "w"
        assert call_kwargs["safe_search"] is False
        assert call_kwargs["search_snippets_only"] is False
        assert call_kwargs["search_language"] == "German"
        assert call_kwargs["max_filtered_results"] == 10

    @patch("local_deep_research.config.search_config.factory_get_search")
    @patch("local_deep_research.config.search_config.get_llm")
    @patch("local_deep_research.config.search_config.get_setting_from_snapshot")
    def test_returns_none_when_factory_fails(
        self, mock_get_setting, mock_get_llm, mock_factory
    ):
        """Should return None when factory returns None."""
        mock_get_setting.side_effect = lambda key, default, **kwargs: default
        mock_get_llm.return_value = MagicMock()
        mock_factory.return_value = None

        result = get_search()

        assert result is None
